为什么logger.info()仅在调用logging.info()之后出现? [英] Why does logger.info() only appear after calling logging.info()?

查看:948
本文介绍了为什么logger.info()仅在调用logging.info()之后出现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Python 3.6.4.我首先遇到一个忽略了logger.setLevel(logging.INFO)的问题,并遇到了此答案,这使我感到困惑,并引起了这个问题问题.

I am using Python 3.6.4. I first encountered an issue where logger.setLevel(logging.INFO) was ignored, and came across this answer, which confused me and gave rise to this question.

给出以下代码,

1.为何logging.info('2')在代码段2中而不是在1中打印?(logging.info()不是模块级功能吗?为什么命名记录器会影响此调用?)

1. Why does logging.info('2') get printed in Snippet 2, but not in 1? (Isn't logging.info() is a module level function? Why does naming a logger affect this call?)

2.为什么要打印logger.info('3'),而不打印logger.info('1')?

2. Why does logger.info('3') get printed, but not 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对象:

As you point out, the difference between the snippets is in how you get the logger object:

logger = logging.getLogger('foo')
logger = logging.getLogger()

关键是在第二种情况下,您将获得"root"记录器.另一方面,在第一种情况下,您将获得根的名为foo.

The key thing is that, in the second case, you are getting the "root" logger. In the first case, on the other hand, you are getting a "sublogger" of the root called foo.

现在,让我们逐步进行.

Now, let's go step by step.

logger.setLevel(logging.INFO)

在这里设置记录器的级别.在第一种情况下,您要设置记录器foo的级别.创建时,新的记录器没有级别,因此它们会处理每条消息.在这里,您是说只处理严重性为INFO或更高的消息.但是,在第二种情况下,logger是根记录器.令人困惑的是,与新记录器不同,根记录器的默认级别为WARN,因此,除非您进行更改,否则不会处理低于该级别的任何内容.因此,在此行之后:

Here you set the level of the logger. In the first case, you are setting the level for the logger foo. On creation, new loggers do not have a level, so they process every message; here you are saying that only messages with severity INFO or higher should be processed. But, in the second case, logger is the root logger. The confusing bit here is that, unlike new loggers, the root logger default level is WARN, so nothing below that level is processed unless you change it. So, after this line:

  • 在第一个代码段中,根记录器设置为WARN级别,而foo记录器设置为INFO级别.
  • 在第二个片段中,根记录器设置为INFO级别.
  • In the first snippet, the root logger is set to WARN level, and the foo logger is set to INFO level.
  • In the second snippet, the root logger is set to INFO level.
logger.info('1')

第一条记录的行.在这两种情况下,您都具有相同的行为.消息为INFO,并且logger设置为该严重性,因此将对消息进行处理.但是,您没有在logger中设置任何处理程序,因此该消息实际上什么也没做.

First logged line. Here you have the same behavior in both cases. The message is INFO, and logger is set to that severity, so the message is processed. However, you do not have any handler set in logger, so nothing is actually done with the message.

logging.info('2')

现在,这更有趣.重要的是logging.info的实际作用,这与调用根记录器对象的info方法不同:

Now this is more interesting. What is important here is what logging.info actually does, which is not the same as if you call the info method of the root logger object:

在根记录器上记录严重性为"INFO"的消息.如果记录仪有 没有处理程序,请调用basicConfig()以添加具有预定义的控制台处理程序 格式.

Log a message with severity 'INFO' on the root logger. If the logger has no handlers, call basicConfig() to add a console handler with a pre-defined format.

因此,如果没有为根记录器注册任何处理程序,则此函数将自行创建控制台处理程序.因此,由根记录器或子记录器收到的任何消息现在都将打印到控制台.但是,在第一种情况下,事实证明根记录器仍具有其默认的严重性过滤器WARN,因此已注册控制台处理程序,但实际上忽略了该消息.但是,在第二种情况下,您将根记录程序的严重性级别设置为INFO,因此消息由控制台处理程序处理和打印.

So, this function will make a console handler by itself if no handlers are registered for the root logger. So any message received by the root logger or subloggers will now be printed to console. In the first case, however, turns out that the root logger has still its default severity filter, WARN, so the console handler is registered, but the message is actually ignored. In the second case, though, you set the severity level of the root logger to INFO, so the message is processed and printed by the console handler.

logger.info('3')

希望这应该现在有意义.现在,您已将控制台处理程序附加到根记录器.在第一种情况下,loggerfoo记录器,其严重性设置为INFO,因此将处理该消息,并且由于它是根记录器的子记录器,因此由注册的控制台处理程序打印该消息.为了那个.在第二种情况下,您只是登录到具有INFO严重性和已注册控制台处理程序的root记录器.

Hopefully this should make sense now. Now you have a console handler attached to the root logger. In the first case, logger is the foo logger, and its severity is set to INFO, so the message is processed and, since it is a sublogger of the root logger, it is printed by the console handler registered for that one. In the second case, you are just logging to the root logger, which has INFO severity and the registered console handler.

请注意,在第一种情况的最后一行中,即使根记录器的严重性级别为WARN,由foo记录器处理的消息也由在根记录器中注册的处理程序处理.日志处理程序不负责按严重性进行过滤,这是由记录器本身完成的,因此,一旦记录器决定了应该处理的消息,它将由其所有处理程序以及来自父记录器的处理程序进行处理.这是一项非常有用的功能,因为它使您可以具有较高的系统级日志级别,而对于您更感兴趣的特定模块(例如,用于调试或简单地报告)则具有较低的日志级别.

Note that in the last line of the first case, the message processed by the foo logger is handled by the handler registered in the root logger even though the severity level of the root logger is WARN. Log handlers are not responsible for filtering by severity, that is done by the logger itself, so once a logger has decided that a message should be processed, it is handled by all its handlers and the handlers from parent loggers. This is a very useful feature, since it allows you to have a higher system-level log level and a lower one for specific modules that you are more interested in (e.g. for debugging or simply reporting).

这篇关于为什么logger.info()仅在调用logging.info()之后出现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆