Why is logging behaving this way in python -
so, recently, i've experienced weird behaviour in project, did small test reproduce behaviour. here complete code:
import logging logging import config config.dictconfig({ 'version': 1, 'formatters': { 'fmt_root': {'format': '[ / ] - %(levelname)s - %(name)s - %(message)s'}, 'fmt_pkg': {'format': '[ /pkg ] - %(levelname)s - %(name)s - %(message)s'}, 'fmt_pkg_sub': {'format': '[ /pkg/sub ] - %(levelname)s - %(name)s - %(message)s'}, }, 'handlers': { 'hnd_root': { 'class': 'logging.streamhandler', 'level': logging.debug, 'stream': 'ext://sys.stdout', 'formatter': 'fmt_root', }, 'hnd_pkg': { 'class': 'logging.streamhandler', 'level': logging.debug, 'stream': 'ext://sys.stdout', 'formatter': 'fmt_pkg', }, 'hnd_pkg_sub': { 'class': 'logging.streamhandler', 'level': logging.debug, 'stream': 'ext://sys.stdout', 'formatter': 'fmt_pkg_sub', }, }, 'root': { 'handlers': ['hnd_root'], 'level': logging.debug, }, 'loggers': { 'pkg': { 'handlers': ['hnd_pkg'], 'level': logging.warning, 'propagate': true, }, 'pkg.sub': { 'handlers': ['hnd_pkg_sub'], 'level': logging.info, 'propagate': true, }, }, }) logging.getlogger().info('message 1') logging.getlogger('pkg').info('message 2') logging.getlogger('pkg.sub').info('message 3')
output of small program is:
[ / ] - info - root - message 1 [ /pkg/sub ] - info - pkg.sub - message 3 [ /pkg ] - info - pkg.sub - message 3 [ / ] - info - pkg.sub - message 3
now, isn't output naturally expect. why "message 2" not logged on root logger (message level info, root accepts debug level) , why "message 3" logged on 'pkg' logger (message level info, pkg accepts warning)?
i did research , found message level checked against logger message posted directly - parent logger levels root not checked, handler levels checked. this seems odd me. there explanation of this? why behave way? use cases this?
ps: behaviour expecting code exact thing if switched handler , logger levels around:
[ / ] - info - root - message 1 [ / ] - info - pkg - message 2 [ /pkg/sub ] - info - pkg.sub - message 3 [ / ] - info - pkg.sub - message 3
the logger's level used first, go/no go check. because can have multiple handlers logger. example, have filehandler writes disk info
, above , smtphandler emails critical
.
if passes check log sent loggers handlers, , when propagate set true
, it's sent handlers of parent loggers of log called, ignoring level check in loggers.
this way, message 2
not printed @ all, because not pass logger's level check, message 3
print 3 times, because logger set lower level info'
, , handlers \
, pkg
, pgk.sub
set @ lower level info
.
in short, logger level means "should send handlers?" , handler level means "should write disk/console/socket etc.?".
example 1.
logger | logger level | handler level / | critical | debug pkg | critical | debug pkg.sub | debug | debug
using logging.getlogger('pkg.sub').debug('message 3')
print :
[ /pkg/sub ] - debug - pkg.sub - message 3 [ /pkg ] - debug - pkg.sub - message 3 [ / ] - debug - pkg.sub - message 3
example 2.
logger | logger level | handler level / | critical | info pkg | critical | debug pkg.sub | debug | debug
using logging.getlogger('pkg.sub').debug('message 3')
print :
[ /pkg ] - debug - pkg.sub - message 3 [ / ] - debug - pkg.sub - message 3
example 3.
logger | logger level | handler level / | critical | debug pkg | critical | info pkg.sub | debug | debug
using logging.getlogger('pkg.sub').debug('message 3')
print :
[ /pkg/sub ] - debug - pkg.sub - message 3 [ / ] - debug - pkg.sub - message 3
in order result want, need setup :
logger | logger level | handler level / | debug | debug pkg | info | warning pkg.sub | info | debug
Comments
Post a Comment