关于python日志记录中的NOTSET

时间:2014-02-01 05:26:16

标签: python logging

正如logger.setLevel doc所说:

  

创建记录器时,级别设置为NOTSET(当记录器是根记录器时会导致处理所有消息,或者当记录器是非root记录器时委托给父级)。请注意,根记录器的创建级别为WARNING。

所以我想如果我用级别NOTSET创建一个根记录器,将显示调试和信息日志。

代码使用basicConfig将根记录器的级别设置为NOTSET是正确的:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

logging.basicConfig(level=logging.NOTSET)
log = logging.getLogger()

log.debug('debug')
log.info('info')
log.warning('warning')
log.error('error')
log.critical('critical')

,输出为:

DEBUG:root:debug
INFO:root:info
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical

但是,如果我创建一个根记录器,并向其添加NOTSET级别的处理程序,例如:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

log = logging.getLogger()
hd = logging.StreamHandler()
hd.setLevel(logging.NOTSET)
log.addHandler(hd)

log.debug('debug')
log.info('info')
log.warning('warning')
log.error('error')
log.critical('critical')

输出是:

warning
error
critical

但我认为它也会输出调试和信息消息。

2 个答案:

答案 0 :(得分:5)

好的,我误解了文档中的Logger's levelHandler's Level

  

setLevel()方法与logger对象一样,指定将分派到适当目标的最低严重性。为什么有两个setLevel()方法?记录器中设置的级别确定将传递给其处理程序的消息的严重性。每个处理程序中设置的级别确定处理程序将发送哪些消息。

如果我将代码更改为此,则可以:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

log = logging.getLogger()
log.setLevel(logging.NOTSET) # Set Logger's level to NOTSET, default is WARNING
#print "Logger's Level: ", log.level
hd = logging.StreamHandler()
hd.setLevel(logging.NOTSET)
#print "Handler's Level: ", hd.level
log.addHandler(hd)

log.debug('debug')
log.info('info')
log.warning('warning')
log.error('error')
log.critical('critical')

答案 1 :(得分:0)

让我们以示例的方式说明,在创建记录器的具体实例时,UNSET不会做任何事情(出于某种神秘的原因):

def logging_unset_level():
    """My sample logger explaining UNSET level

    Resources: 
    - https://stackoverflow.com/questions/21494468/about-notset-in-python-logging
    - https://www.youtube.com/watch?v=jxmzY9soFXg&t=468s
    - https://github.com/CoreyMSchafer/code_snippets/tree/master/Logging-Advanced
    """
    import logging

    logger = logging.getLogger(__name__) # loggers are created in hierarchy using dot notation, thus __name__ ensures no name collisions.
    print(f'DEFAULT VALUE: logger.level = {logger.level}')

    file_handler = logging.FileHandler(filename='my_log.log')
    log_format = "{asctime}:{levelname}:{lineno}:{name}:{message}" # see for logrecord attributes https://docs.python.org/3/library/logging.html#logrecord-attributes
    formatter = logging.Formatter(fmt=log_format, style='{') 
    file_handler.setFormatter(fmt=formatter) 

    stdout_stream_handler = logging.StreamHandler(stream=sys.stdout)
    stdout_stream_handler.setLevel(logging.INFO) 
    log_format = "{name}:{levelname}:-> {message}" # see for logrecord attributes https://docs.python.org/3/library/logging.html#logrecord-attributes
    formatter = logging.Formatter(fmt=log_format, style='{')
    stdout_stream_handler.setFormatter(fmt=formatter)

    logger.addHandler(hdlr=file_handler)
    logger.addHandler(hdlr=stdout_stream_handler)

    logger.log(logging.NOTSET, 'notset')
    logger.debug('debug')
    logger.info('info')
    logger.warning('warning')
    logger.error('error')
    logger.critical('critical')

屏幕输出为:

DEFAULT VALUE: logger.level = 0
__main__:WARNING:-> warning
__main__:ERROR:-> error
__main__:CRITICAL:-> critical

stdout的输出是:

2020-04-15 17:00:38,384:WARNING:200:__main__:warning
2020-04-15 17:00:38,384:ERROR:201:__main__:error
2020-04-15 17:00:38,384:CRITICAL:202:__main__:critical
如问题正文所预期的那样,

实例化记录器时,其设置为UNSET。如果您出于某种原因使用基本配置,则它确实可以正常工作,因为文档暗示在实例化记录程序时,应该从UNSET到更高版本的所有记录 BUT,但此设置仅会使错误消息出于某些原因起作用(查找给我一个参考!)。

好吧,现在,如果再次运行它,但又增加了顶级记录器的级别,一切都会按预期运行(未设置的除外):

logger.setLevel(logging.DEBUG)

stdout的输出(出于教学原因,在我的示例中,stdout处理程序的级别为INFO,与文件处理程序不同,试图显示顶级记录器对.level值的继承)。

DEFAULT VALUE: logger.level = 10
__main__:INFO:-> info
__main__:WARNING:-> warning
__main__:ERROR:-> error
__main__:CRITICAL:-> critical

和记录器文件my_log.log的输出(这确实输出调试语句!:D):

2020-04-15 17:05:58,782:DEBUG:198:__main__:debug
2020-04-15 17:05:58,784:INFO:199:__main__:info
2020-04-15 17:05:58,784:WARNING:200:__main__:warning
2020-04-15 17:05:58,784:ERROR:201:__main__:error
2020-04-15 17:05:58,784:CRITICAL:202:__main__:critica

符合预期。它继承了顶层记录器级别,因此可以打印从调试级别开始的所有内容。