繁体   English   中英

为什么 logger.info() 只有在调用 logging.info() 后才会出现?

[英]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')

片段 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

片段 2

>>> 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')

希望这现在应该是有意义的。 现在您有一个附加到根记录器的控制台处理程序。 在第一种情况下, loggerfoo记录器,其严重性设置为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.

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