使用QueueHandler和QueueListener进行Python日志记录(logutils)

Hos*_*Hos 5 python queue logging multiprocessing

多进程python应用需要记录日志。使用队列似乎是最好的解决方案。logutils库提供了此功能。

是否可以分别设置两个处理程序的日志级别?例如,在下面的测试中,我希望STREAM 1具有警告消息,STREAM 2具有INFO消息。在代码末尾的测试日志中,将创建一个INFO消息,该消息不应从STREAM 1处理程序输出到控制台(警告)。但是,它输出到两个处理程序。

作为参考,我一直在使用该库的作者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()
Run Code Online (Sandbox Code Playgroud)

Gio*_*tto 5

您可以使用从 Python 3.5 版respect_handler_level开始添加到QueueListener初始化程序的参数,以便侦听器将尊重处理程序的各个级别。

来自QueueListener的文档

如果respect_handler_levelTrue,则在决定是否将消息传递给该处理程序时会考虑处理程序的级别(与消息的级别相比);否则,行为与以前的 Python 版本一样 - 始终将每条消息传递给每个处理程序。

在您的情况下,您应该将初始化替换QueueListener为:

ql = QueueListener(q, h1, h2, respect_handler_level=True)
Run Code Online (Sandbox Code Playgroud)


Vin*_*jip 2

这是该方法的实施中的限制QueueListener.handle()。目前是:

def handle(self, record):
    record = self.prepare(record)
    for handler in self.handlers:
        handler.handle(record)
Run Code Online (Sandbox Code Playgroud)

要做自己想做的事,就应该这样

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)
Run Code Online (Sandbox Code Playgroud)

我会在某个时候修复这个问题,因为我认为这更好,但现在您可以子类化QueueListener并重写handle子类中的方法。