[英]Using logging.info instead of logger.info wrecks StreamHandler
[英]Why does logger.info() only appear after calling logging.info()?
我正在使用 Python 3.6.4。 我第一次遇到logger.setLevel(logging.INFO)
被忽略的问题,并遇到了这个答案,这让我感到困惑并产生了这个问题。
鉴于下面的代码,
1. 为什么
logging.info('2')
打印在 Snippet 2 中,而不是 1? (logging.info()
不是模块级函数吗?为什么命名记录器会影响这个调用?)2. 为什么
logger.info('3')
被打印出来,而不是logger.info('1')
?
>>> import logging
>>> logger = logging.getLogger('foo') # named logger
>>> logger.setLevel(logging.INFO)
>>> logger.info('1')
>>> logging.info('2') # prints nothing
>>> logger.info('3')
INFO:foo:3
>>> import logging
>>> logger = logging.getLogger() # no name
>>> logger.setLevel(logging.INFO)
>>> logger.info('1')
>>> logging.info('2') # printed
INFO:root:2
>>> logger.info('3')
INFO:root:3
正如您所指出的,片段之间的区别在于您如何获取logger
对象:
logger = logging.getLogger('foo')
logger = logging.getLogger()
关键是,在第二种情况下,您将获得“根”记录器。 另一方面,在第一种情况下,您将获得名为foo
的根的“子记录器”。
现在,让我们一步一步来。
logger.setLevel(logging.INFO)
在这里设置记录器的级别。 在第一种情况下,您正在设置记录器foo
的级别。 创建时,新记录器没有级别,因此它们处理每条消息; 在这里,您是说只应处理严重性为INFO
或更高的消息。 但是,在第二种情况下, logger
是根记录器。 这里令人困惑的一点是,与新的记录器不同,根记录器的默认级别是WARN
,因此除非您更改它,否则不会处理低于该级别的任何内容。 所以,在这一行之后:
WARN
级别,而foo
记录器设置为INFO
级别。INFO
级别。logger.info('1')
第一个记录的行。 在这里,您在两种情况下都有相同的行为。 该消息是INFO
,并且logger
设置为该严重性,因此该消息被处理。 但是,您没有在logger
设置任何处理程序,因此实际上没有对消息进行任何处理。
logging.info('2')
现在这更有趣。 这里重要的是logging.info
实际做了什么,这与调用根记录器对象的info
方法不同:
在根记录器上记录严重性为“INFO”的消息。 如果记录器没有处理程序,请调用 basicConfig() 以添加具有预定义格式的控制台处理程序。
因此,如果没有为根记录器注册处理程序,此函数将自行创建一个控制台处理程序。 因此,根记录器或子记录器收到的任何消息现在都将打印到控制台。 然而,在第一种情况下,根记录器仍然具有其默认的严重性过滤器WARN
,因此控制台处理程序已注册,但消息实际上被忽略了。 但是,在第二种情况下,您将根记录器的严重性级别设置为INFO
,因此消息由控制台处理程序处理和打印。
logger.info('3')
希望这现在应该是有意义的。 现在您有一个附加到根记录器的控制台处理程序。 在第一种情况下, logger
是foo
记录器,其严重性设置为INFO
,因此消息被处理,并且由于它是根记录器的子记录器,因此它由为该记录器注册的控制台处理程序打印。 在第二种情况下,您只是登录到具有INFO
严重性和已注册控制台处理程序的根记录器。
请注意,在第一种情况的最后一行,由foo
记录器处理的消息由在根记录器中注册的处理程序处理,即使根记录器的严重性级别是WARN
。 日志处理程序不负责按严重性过滤,这是由记录器本身完成的,所以一旦记录器决定应该处理一条消息,它就会由它的所有处理程序和来自父记录器的处理程序处理。 这是一个非常有用的功能,因为它允许您拥有更高的系统级日志级别,并为您更感兴趣的特定模块(例如,用于调试或简单报告)设置更低的日志级别。
请参阅该帖子上已接受的答案:
如果您没有使用任何处理程序配置日志记录(如在您的帖子中 - 您只为您的记录器配置一个级别,但在任何地方都没有处理程序),您将获得一个内部处理程序“最后的手段”,该处理程序设置为仅输出
WARNING
级别的消息(没有其他格式)。
您的级别当前低于WARNING
,因此不会输出。 这会随着对basicConfig()
的调用而basicConfig()
,您可以/应该显式调用它,否则它不会被处理,直到从logging.info
(或其他便利函数之一)调用它。
文档观察到这一点:
注意上面的模块级便捷函数委托给根记录器,调用
basicConfig()
以确保至少有一个处理程序可用。 因此,它们不应在线程中使用,在早于 2.7.1 和 3.2 的 Python 版本中,除非在启动线程之前至少已将一个处理程序添加到根记录器。 在早期版本的 Python 中,由于basicConfig()
的线程安全缺陷,这可能(在极少数情况下)导致处理程序被多次添加到根记录器,这反过来又会导致同一事件的多条消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.