Help me understand the python logging module and its handlers

I really missed something in common about the python registration module.

In the following code, I create a logger ( log ) object and add two handlers to it. One with INFO Level and one WARNING Level. Both of them should print to standard output. I expect that calling log.info(msg) will result in one copy of msg in my stdout and calling log.warn(msg) . in two msg instances printed on my stdout. Here is the code:

 import logging import sys logging.basicConfig() log = logging.getLogger('myLogger') log.handlers = [] h1 = logging.StreamHandler(sys.stdout) h1.level = logging.INFO h1.formatter = logging.Formatter('H1 H1 %(message)s ') h2 = logging.StreamHandler(sys.stdout) h2.level = logging.WARNING h2.formatter = logging.Formatter('H2 H2 %(message)s') log.addHandler(h1) log.addHandler(h2) print 'log.level == %s'%logging.getLevelName(log.level) print 'log.info' log.info('this is some info') print 'done' print 'log.warn' log.warn('this is a warning') print 'done' 

The exit is really very strange for me. Calling .info does not have a visual effect. However, when you call warn two copies of the msg message printed on stdout are displayed (this is normal), but also one copy printed on stderr (why?). This is the result of the above code. Note the formatting of the last line on this output. This line is printed on stderr.

 log.level == NOTSET log.info done log.warn H1 H1 this is a warning H2 H2 this is a warning done WARNING:myLogger:this is a warning 

So my questions are:

  • Why does my info call fail to exit even though h1 set to INFO?
  • Why does my warn call lead to additional output in stderr?
+6
source share
2 answers

You need to know two things:

  • The root logger is initialized with the WARNING level.

    Any journal message that reaches the registrar is discarded if its level is lower than the registrar. If the registrar level is not set, it takes its "effective level" from its parent registrar. Therefore, if the root registrar has a WARNING level, all registrars have an effective default level of WARNING . Unless you configure it differently, all log messages below which will be discarded.

  • When you call basicConfig() , the system automatically sets the StreamHandler in the root log, which prints to the standard error stream.

    When your program displays its log messages, there are actually three handlers: two that you added that have their own levels, and one from the system that prints any message that is not rejected by its logger. That is why you get the string

     WARNING:myLogger:this is a warning 

    It comes from the system registrar. He does not do this for INFO level messages because, as discussed earlier, the root logger is configured to reject these messages by default.

    If you do not want this output, do not call basicConfig() .

Further reading: http://docs.python.org/howto/logging.html

+7
source

There are actually five levels of logging: debug, info, warning, error, and critical. I see that when setting up your registrar, you obviously do not set your level - I believe that the registrar can warn by default if the level is not set.

Due to the fact that he repeatedly prints for warning, I believe that this is due to the creation of two handlers for information and warning. What happens is that the logger cascades in severity from the warning → info → debug, invoking a handler for each. Since your level is set to warning, the information handler is ignored. In addition, I believe that warning messages are usually logged in sys.stderr.

Try the following:

 logging.basicConfig(level=logging.INFO) 

See also:

+3
source

Source: https://habr.com/ru/post/897854/


All Articles