7

在我的程序中,我在开头定义了一个类似于以下内容的记录器:

def start_logger():
        fh = logging.handlers.RotatingFileHandler('logger.log', 
                                                  maxBytes=1000000, 
                                                  backupCount=100)
        fh.setLevel(logging.DEBUG)

        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(logging.DEBUG)

        fh_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'
        #fh_fmt = '%(asctime)s - %(funcName)s - %(levelname)s - %(message)s'

        ch_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'
        #ch_fmt = '%(funcName)s - %(levelname)s - %(message)s'

        fh.setFormatter(logging.Formatter(fh_fmt))
        ch.setFormatter(logging.Formatter(ch_fmt))

        root = logging.getLogger()
        root.addHandler(fh)
        root.addHandler(ch)

然后我有多个从我的主程序调用的文件。为了让它们正常工作,我需要执行以下操作:

import logging
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
log.debug("This debug message is ounly output when I set the level again to debug for this file. Otherwise the the log level for this file is WARNING.")

为什么我导入的所有模块的默认级别都设置为警告。为什么当他们使用 log = logging.getLogger( name ) 导入我的根记录器时,我必须再次为他们每个人设置级别为 DEBUG?这是在具有不同模块的包中创建日志记录模块的最佳方法还是有更好的解决方案?

4

1 回答 1

10

让我们先看看 Handler.setLevel了什么:

将此处理程序的阈值设置为 lvl。比 lvl 严重程度低的日志消息将被忽略。创建处理程序时,级别设置为 NOTSET(这会导致处理所有消息)。

任何低于 lvl 严重程度的消息都会被忽略。实际上,将其设置为 DEBUG 是没有意义的(除非您定义自己的日志级别),因为没有比调试更严重的消息。因此,这意味着处理程序不会忽略任何消息。

setLevel是正确的想法,但你在错误的对象上调用它。看看Logger.setLevel

将此记录器的阈值设置为 lvl。比 lvl 严重程度低的日志消息将被忽略。创建记录器时,级别设置为 NOTSET(当记录器是根记录器时会处理所有消息,或者当记录器是非根记录器时会委托给父级)。请注意,根记录器是使用 WARNING 级别创建的。

术语“委托给父级”意味着如果记录器具有 NOTSET 级别,则遍历其祖先记录器链,直到找到具有 NOTSET 级别以外的祖先,或者到达根。

如果找到具有 NOTSET 级别的祖先,则该祖先的级别被视为祖先搜索开始的记录器的有效级别,并用于确定如何处理日志记录事件。

您正在创建正确的孩子,但他们都是根记录器的孩子。它们的级别设置为NOTSET,并且它传播到根,其默认值为WARNING。因此,您看不到任何消息。

TL;DR: 解决方案很简单:在记录器上设置级别,而不是在处理程序上。以下代码应该可以满足您的需求:

def start_logger():
    fh = logging.handlers.RotatingFileHandler('logger.log', 
                                              maxBytes=1000000, 
                                              backupCount=100)

    ch = logging.StreamHandler(sys.stdout)

    fh_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'
    #fh_fmt = '%(asctime)s - %(funcName)s - %(levelname)s - %(message)s'

    ch_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'
    #ch_fmt = '%(funcName)s - %(levelname)s - %(message)s'

    fh.setFormatter(logging.Formatter(fh_fmt))
    ch.setFormatter(logging.Formatter(ch_fmt))

    logging.basicConfig(level=logging.DEBUG)
    root = logging.getLogger()
    root.addHandler(fh)
    root.addHandler(ch)

一旦你这样做了,你在制作孩子时就不需要setLevel打电话了。

哦,回答你的其他问题:这正是你应该使用日志库的方式。(实际上我只是将所有内容都记录到根记录器中,因为我不需要您开发的那种粒度,但是当您有需要时,您会按照您应该做的那样做。)

编辑:显然, setLevel 似乎不适用于根记录器。相反,在访问根记录器之前,您必须设置 basicConfig。设置级别logging.basicConfig将满足您的需求(至少,它在我的测试中有效)。请注意,这样做与Logging from multiple modules中给出的示例相匹配,因此应该可以解决您的问题。

于 2017-06-27T17:41:22.993 回答