【问题标题】:Python logging: propagate messages of level below current logger levelPython日志记录:传播低于当前记录器级别的消息
【发布时间】:2013-08-06 04:46:15
【问题描述】:

我想将特定记录器名称、特定级别和更高级别(例如INFO 及更高级别)的消息记录到特定日志处理程序,例如文件处理程序,同时仍将所有日志消息发送到控制台。 Python 是 2.7 版。

到目前为止,我尝试的是创建两个记录器:

  • 根记录器
  • 命名记录器

对于根记录器,我附加了一个logging.StreamHandler,并将日志级别设置为logging.DEBUG

然后我将一个处理程序附加到指定的记录器,并将该记录器的级别设置为logging.INFO

当我现在调用使用命名记录器的模块时,我不再将DEBUG 日志传播到根记录器。

注意:extraLogger 在这里有一个 StreamHandler 来演示问题。在我的生产代码中,我会使用 FileHandler

import logging

def do_logging(turn):
    logger = logging.getLogger('extra')
    logger.info('some info turn %d' % turn) 
    logger.debug('this is debug fudge turn %d' % turn)

rootLogger = logging.getLogger()
handler = logging.StreamHandler()
rootFormatter = logging.Formatter('root - %(levelname)s: %(msg)s')
handler.setFormatter(rootFormatter)
rootLogger.addHandler(handler)
rootLogger.setLevel(logging.DEBUG)

do_logging(1)

extraLogger = logging.getLogger('extra')
extraHandler = logging.StreamHandler()
extraFormatter = logging.Formatter('extra - %(levelname)s: %(msg)s')
extraHandler.setFormatter(extraFormatter)
extraLogger.addHandler(extraHandler)
extraLogger.setLevel(logging.INFO)

do_logging(2)

实际输出:

root - INFO: some info turn 1
root - DEBUG: this is debug fudge turn 1
extra - INFO: some info turn 2
root - INFO: some info turn 2

我想要的输出:

root - INFO: some info turn 1
root - DEBUG: this is debug fudge turn 1
extra - INFO: some info turn 2
root - INFO: some info turn 2
root - DEBUG: this is debug fudge turn 2

我怀疑自定义 Filter 在这种情况下会有所帮助,但我不知道如何...

【问题讨论】:

    标签: python logging python-2.7 handler


    【解决方案1】:

    你可以像这样使用robert's LevelFilter

    # Put the Filter on the Handler so only INFO and higher is handled
    extraHandler.addFilter(LevelFilter(logging.INFO))
    
    # Let the Logger process everything (so it can propagate records to root)
    extraLogger.setLevel(logging.DEBUG)
    

    import logging
    
    class LevelFilter(logging.Filter):
        """
        https://stackoverflow.com/a/7447596/190597 (robert)
        """
        def __init__(self, level):
            self.level = level
    
        def filter(self, record):
            return record.levelno >= self.level
    
    def do_logging(turn):
        logger = logging.getLogger('extra')
        logger.info('some info turn %d' % turn) 
        logger.debug('this is debug fudge turn %d' % turn)
    
    rootLogger = logging.getLogger()
    handler = logging.StreamHandler()
    rootFormatter = logging.Formatter('root - %(levelname)s: %(msg)s')
    handler.setFormatter(rootFormatter)
    rootLogger.addHandler(handler)
    rootLogger.setLevel(logging.DEBUG)
    do_logging(1)
    
    extraLogger = logging.getLogger('extra')
    extraHandler = logging.StreamHandler()
    extraFormatter = logging.Formatter('extra - %(levelname)s: %(msg)s')
    extraHandler.setFormatter(extraFormatter)
    extraLogger.addHandler(extraHandler)
    
    # Put the Filter on the Handler so only INFO and higher is handled
    extraHandler.addFilter(LevelFilter(logging.INFO))
    
    # Handle everything (so it can propagate to root)
    extraLogger.setLevel(logging.DEBUG)
    do_logging(2)
    

    【讨论】:

    • 工作正常,非常感谢。似乎在记录器基于裸级别机制丢弃日志条目之后,它不再传播它们。在这里,通过将日志级别设置为较低来解决此问题,但仅记录所需级别的日志消息,这样可以传播较低级别的日志条目。
    • 是的,没错。有一个nice flow chart in the docs 设置了正确的心智模型。您不希望附加到记录器的过滤器拒绝记录,因为它永远不会进入传播步骤。
    • 哦,如果过滤器附加到处理程序或记录器会有很大的不同...... 处理程序子图表似乎具有误导性:停止 不会停止处理,只是从该处理程序返回而不发出任何内容,并且流程将传递到下一个处理程序,或者我错了,@unutbu?
    • 你是对的; Stop 不会停止处理。它只是停止该子图表。并且涉及到一个循环,因为可能有多个处理程序。因此,如果有一个处理程序,控制流将转到下一个处理程序,最后返回主流程图。对于确切的故事go to the source
    【解决方案2】:

    记录器类中有一个名为“propagate”的方法似乎可以满足您的要求:http://docs.python.org/2/library/logging.html#logger-objects

    【讨论】:

    • AFAIU Logger.propagate 是一个布尔属性,用于控制是否发生传播。我试图解决这个问题,但似乎日志条目会根据级别被丢弃,因此无论如何都不会传播到根记录器。
    猜你喜欢
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    相关资源
    最近更新 更多