简体   繁体   English

默认情况下,python logger级别从root设置继承为警告

[英]python logger level inherited from root set to warning by default

In my program I define a logger at the beginning that looks similar to this: 在我的程序中,我在开头定义了一个类似于此的记录器:

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)

I then have multiple files that are called from my main program. 然后我有多个从我的主程序调用的文件。 In order for them to work correctly I need to do the following: 为了使它们正常工作,我需要执行以下操作:

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.")

Why is the default level for all modules that I import set to warning. 为什么我导入的所有模块的默认级别都设置为警告。 Why do I have to set the level again to DEBUG for each of them when they import my root logger with log = logging.getLogger( name )? 为什么在使用log = logging.getLogger( name )导入root记录器时,必须为每个级别再次设置DEBUG级别? Is this the best way to create a logging module accross a package with different modules or is there a better solution? 这是在具有不同模块的包中创建日志记录模块的最佳方法,还是有更好的解决方案?

Let's start by looking at what Handler.setLevel does : 让我们从查看Handler.setLevel的作用开始

Sets the threshold for this handler to lvl. 将此处理程序的阈值设置为lvl。 Logging messages which are less severe than lvl will be ignored. 记录不如lvl严重的消息将被忽略。 When a handler is created, the level is set to NOTSET (which causes all messages to be processed). 创建处理程序时,级别设置为NOTSET(这会导致处理所有消息)。

Any messages less severe than lvl are ignored. 任何不如lvl严重的消息都会被忽略。 Effectively, setting it to DEBUG is meaningless (unless you define your own log levels), because there is no less severe message than debug. 实际上,将其设置为DEBUG是没有意义的(除非您定义自己的日志级别),因为没有比调试更严重的消息。 So, that means that the handler won't ignore any messages. 所以,这意味着处理程序不会忽略任何消息。

setLevel is the right idea, but you're calling it on the wrong object. setLevel是正确的想法,但你在错误的对象上调用它。 Look at Logger.setLevel : 看看Logger.setLevel

Sets the threshold for this logger to lvl. 将此记录器的阈值设置为lvl。 Logging messages which are less severe than lvl will be ignored. 记录不如lvl严重的消息将被忽略。 When a logger is created, the level is set to NOTSET (which causes all messages to be processed when the logger is the root logger, or delegation to the parent when the logger is a non-root logger). 创建记录器时,级别设置为NOTSET(当记录器是根记录器时会导致处理所有消息,或者当记录器是非root记录器时委托给父级)。 Note that the root logger is created with level WARNING. 请注意,根记录器是使用级别WARNING创建的。

The term 'delegation to the parent' means that if a logger has a level of NOTSET, its chain of ancestor loggers is traversed until either an ancestor with a level other than NOTSET is found, or the root is reached. 术语“委托给父母”意味着如果记录器具有NOTSET级别,则遍历其祖先记录器链,直到找到具有NOTSET以外级别的祖先,或者到达根。

If an ancestor is found with a level other than NOTSET, then that ancestor's level is treated as the effective level of the logger where the ancestor search began, and is used to determine how a logging event is handled. 如果发现祖先的级别不是NOTSET,那么祖先的级别将被视为祖先搜索开始的记录器的有效级别,并用于确定如何处理日志记录事件。

You're creating the children right, but they're all children of the root logger. 你正在创建孩子,但他们都是根记录器的孩子。 They're level is set to NOTSET , and it propagates up to the root, whose default value is WARNING . 它们的级别设置为NOTSET ,并传播到根目录,其默认值为WARNING Consequently, you don't see any messages. 因此,您没有看到任何消息。

TL;DR: The solution is simple: set the level on the logger, not the handler. TL; DR:解决方案很简单:在记录器上设置级别,而不是处理程序。 The following code should do what you need: 以下代码应该满足您的需求:

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)

Once you do that, you shouldn't need the setLevel call when making the children. 一旦你这样做,你就不应该在制作孩子时需要setLevel调用。

Oh, and to answer your other questions: this is exactly the way you're supposed to use the logging library. 哦,并回答你的其他问题:这正是你应该使用日志库的方式。 (I actually just log everything to the root logger, because I don't need the kind of granularity you developed, but when you have a case for it, you're doing it just as you should.) (我实际上只是将所有内容记录到根记录器,因为我不需要你开发的那种粒度,但是当你有一个案例时,你就是这样做了。)

EDIT: Evidently, setLevel doesn't seem to work on the root logger. 编辑:显然,setLevel似乎不适用于根记录器。 Instead, before accessing the root logger, you have to set basicConfig. 相反,在访问根记录器之前,您必须设置basicConfig。 Setting the level in logging.basicConfig will do what you need (at least, it worked in my tests). logging.basicConfig设置级别将满足您的需求(至少,它在我的测试中有效)。 Note, doing this matches the example given in Logging from multiple modules , so should solve your problem. 请注意,这样做与从多个模块进行日志记录中给出的示例相匹配,因此应该解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM