2

I know that default level for root logger is warning (30). If I create a non-root logger and if there is no handler defined on that, then the logger will use the level of the root logger (and handler of the root logger). What is the handler level for the root handler?

#assume no root logger is configured and below code gets the non-root logger for the module
logger = logging.getLogger(__name__)
#get effective level - this is inherited from the root logger
print(logger.getEffectiveLevel())
#set the level for this logger to 10
logger.setLevel(10)
#print level which shows 10
print(logger.getEffectiveLevel())
logger.info('this does not get logged')
logger.warning('this gets logged')

How can I get info to print?

variable
  • 8,262
  • 9
  • 95
  • 215
  • There are 2 levels: the level of the logger (which you set to 10) and the level of the handler. Idk the default level of the default handler for a new named logger but if it is higher than DEBUG then that explains it. See [this question](https://stackoverflow.com/questions/17668633/what-is-the-point-of-setlevel-in-a-python-logging-handler). – asachet Oct 21 '19 at 12:03
  • You haven't registered any handlers. Use `logging.basicConfig()` to create a default stream handler on the root logger. – asachet Oct 21 '19 at 12:18
  • This article has some more detail in addition to my answer below: https://realpython.com/python-logging-source-code/ – Brad Solomon Oct 21 '19 at 17:22

1 Answers1

2

The logger doesn't have any handlers explicitly attached to it by default:

>>> logger.handlers
[]

However, in the .callHandlers() method, the logging module will actually fall back to a lastResort handler that has a level of WARNING:

_defaultLastResort = _StderrHandler(WARNING)
lastResort = _defaultLastResort

# ....

    if (found == 0):
        if lastResort:
            if record.levelno >= lastResort.level:
                lastResort.handle(record)

As indicated in the comments, attaching a handler to logger, either viaa basicConfig() or explicitly through addHandler(), and then setting the level of that handler, will mean the logger doesn't fall back to lastResort.

Brad Solomon
  • 38,521
  • 31
  • 149
  • 235
  • Ok so if a handler is attached to a logger (say logger with name as __name__), then, once the log gets handled by the handler, will it get propagated to the root loggers handler (command line - if no root handler is configured)? – variable Oct 21 '19 at 13:28
  • I mean - in presence of handler for a child logger, after the handling log, when the event gets propagated to the root logger, does it fall back to the lastResort handler? – variable Oct 21 '19 at 13:54
  • @variable Yes it does fall back to `lastResort` (and indeed your warning is printed). Keep in mind the `lastResort` handler has level set to `warning` so will not print anything below `warning`, regardless of the level of the logger. This is why your info does not get printed by the `lastResort` handler. A log record must pass both logger level and handler level. In general, you don't care about the handler level (default is `NOTSET` which lets everything pass) but in that particular case the handler level is set in the constructor: `_StderrHandler(WARNING)`. – asachet Oct 21 '19 at 14:16
  • I found [this flowchart](https://stackoverflow.com/a/17670167/3498910) helpful. In particular, the sub-flowchart on the right describes why your `info` is not printed: the level of the `lastResort` handler is higher than `info`. – asachet Oct 21 '19 at 14:18