多进程python应用程序需要进行日志记录。使用队列似乎是最好的解决方案。 logutils库提供了这个。
是否可以单独设置两个处理程序的日志级别?例如,在下面的测试中,我希望STREAM 1有WARNING消息而STREAM 2有INFO消息。在代码末尾的测试日志中,创建了一条INFO消息,该消息不应从STREAM 1处理程序(WARNING)输出到控制台。但是,它输出给两个处理程序。
作为参考,我一直在使用本页的作者Vinay Sajip的这个页面http://plumberjack.blogspot.co.uk/2010/09/improved-queuehandler-queuelistener.html。
# System imports
import logging
import logging.handlers
try:
import Queue as queue
except ImportError:
import queue
# Custom imports
from logutils.queue import QueueHandler, QueueListener
# Get queue
q = queue.Queue(-1)
# Setup stream handler 1 to output WARNING to console
h1 = logging.StreamHandler()
f1 = logging.Formatter('STREAM 1 WARNING: %(threadName)s: %(message)s')
h1.setFormatter(f1)
h1.setLevel(logging.WARNING) # NOT WORKING. This should log >= WARNING
# Setup stream handler 2 to output INFO to console
h2 = logging.StreamHandler()
f2 = logging.Formatter('STREAM 2 INFO: %(threadName)s: %(message)s')
h2.setFormatter(f2)
h2.setLevel(logging.INFO) # NOT WORKING. This should log >= WARNING
# Start queue listener using the stream handler above
ql = QueueListener(q, h1, h2)
ql.start()
# Create log and set handler to queue handle
root = logging.getLogger()
root.setLevel(logging.DEBUG) # Log level = DEBUG
qh = QueueHandler(q)
root.addHandler(qh)
root.info('Look out!') # Create INFO message
ql.stop()
答案 0 :(得分:1)
这是QueueListener.handle()
方法实施的限制。目前这是:
def handle(self, record):
record = self.prepare(record)
for handler in self.handlers:
handler.handle(record)
要做你想做的事,应该是
def handle(self, record):
record = self.prepare(record)
for handler in self.handlers:
# CHANGED HERE TO ADD A CONDITION TO CHECK THE HANDLER LEVEL
if record.levelno >= handler.level:
handler.handle(record)
我会在某些时候解决这个问题,因为我认为这样做会更好,但是现在你可以继承QueueListener
并覆盖子类中的handle
方法。
答案 1 :(得分:1)
我使用此子类来覆盖队列侦听器类。另外两个方法addHandler和removeHandler允许添加和删除处理程序。 CustomQueueListener
应该像QueueListener
一样使用。请按照其他日志记录示例了解如何使用addHandler()
和removeHandler()
。
class CustomQueueListener(QueueListener):
def __init__(self, queue, *handlers):
super(CustomQueueListener, self).__init__(queue, *handlers)
"""
Initialise an instance with the specified queue and
handlers.
"""
# Changing this to a list from tuple in the parent class
self.handlers = list(handlers)
def handle(self, record):
"""
Override handle a record.
This just loops through the handlers offering them the record
to handle.
:param record: The record to handle.
"""
record = self.prepare(record)
for handler in self.handlers:
if record.levelno >= handler.level: # This check is not in the parent class
handler.handle(record)
def addHandler(self, hdlr):
"""
Add the specified handler to this logger.
"""
if not (hdlr in self.handlers):
self.handlers.append(hdlr)
def removeHandler(self, hdlr):
"""
Remove the specified handler from this logger.
"""
if hdlr in self.handlers:
hdlr.close()
self.handlers.remove(hdlr)
答案 2 :(得分:1)
您可以使用从Python 3.5版添加到respect_handler_levels
初始化程序的QueueListener
参数。
如果
respect_handler_level
为True
,则在决定是否将消息传递给该处理程序时,将遵守处理程序的级别(与消息的级别相比);否则,其行为与以前的Python版本相同-始终将每个消息传递给每个处理程序。
在您的情况下,应将QueueListener
的初始化替换为:
ql = QueueListener(q, h1, h2, respect_handler_levels=True)