简体   繁体   中英

Python child logger should report back to root logger instead of applying its own logging configs

As mentioned here https://stackoverflow.com/a/4150322/1526342 . When logging to child logger, it will pass on the message to its parent, and its parent will pass the message to the root logger. Now considering the following example

import logging
import logging.handlers
child_logger = logging.getLogger(__name__)
f = logging.Formatter(
        fmt='%(asctime)s; %(name)s; % (filename)s:%(lineno)d:%(message)s',
        datefmt="%Y-%m-%d %H:%M:%S")
handler = logging.handlers.RotatingFileHandler('/tmp/info.log',
                                               encoding='utf8',
                                               maxBytes=500000000,
                                               backupCount=5)
handler.setFormatter(f)
child_logger.setLevel(logging.INFO)
child_logger.addHandler(handler)
child_logger.info('1 + 1 is %d', 1+1)

child_logger should have reported back to the root logger instead of printing the output to the child_logger's log file.

I'm confused.

As shown in this logging flow chart , loggers pass log records both to own handlers and to parent logger objects. Try adding a handler to the parent logger, you'll see the log record is being processed there as well.

In this case, your 'child_logger' is your root logger. If you had initialized it like so:

logger = getLogger('root')
child_logger = getLogger('root.child')

child_logger is a child of logger as defined by:

The name is potentially a period-separated hierarchical value, like foo.bar.baz (though it could also be just plain foo, for example). Loggers that are further down in the hierarchical list are children of loggers higher up in the list. For example, given a logger with a name of foo, loggers with names of foo.bar, foo.bar.baz, and foo.bam are all descendants of foo. The logger name hierarchy is analogous to the Python package hierarchy, and identical to it if you organise your loggers on a per-module basis using the recommended construction logging.getLogger( __name__ ). That's because in a module, __name__ is the module's name in the Python package namespace.

If you do not want a child to propogate, you can set logger.propagate = False .

Furthermore, if you would like only certain levels written to your child logger file (ie only debug) but you want higher level to still propagate, you could create a subclass of a handler, as in mine here:

from logging import DEBUG, INFO, WARN, ERROR, CRITICAL, handlers

class DebugRotatingFileHandler(handlers.RotatingFileHandler):
    def __init__(self, filename, mode, maxBytes, backupCount, encoding, delay):
        super(DebugRotatingFileHandler, self).__init__(
                  self, filename, mode, maxBytes, backupCount, encoding, delay)

    def emit(self, record):
        if record.levelno != DEBUG:
            return
        super(DebugRotatingFileHandler, self).emit(self, record)

(Yes, I know there are some improvements that can be made, this is old code.)

For example, executing debug_logger.info("Info Message") would print nothing to the debug_logger's specified file, however, if root_logger 's level was set to info, or debug, it would print it out in it's file. I use this for debug logging, whilst still retaining the ability to have the logger make error message calls and print those to the root log.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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