简体   繁体   中英

Python logging: propagate messages of level below current logger level

I want to log messages of a specific logger name, of a certain level and higher (say INFO and up) to a specific log handler, say a file handler, while still getting all log messages to the console. Python is version 2.7.

What I tried until now was to create two loggers:

  • A root logger
  • A named logger

For the root logger, I attached a logging.StreamHandler , and set the log level to logging.DEBUG .

Then I attached a handler to the named logger and set level to logging.INFO for that logger.

When I now call my module, which uses the named logger, I do not get DEBUG logs propagated to the root logger any more.

Note: the extraLogger has a StreamHandler here to demonstrate the issue. In my production code I'd use a FileHandler

import logging

def do_logging(turn):
    logger = logging.getLogger('extra')
    logger.info('some info turn %d' % turn) 
    logger.debug('this is debug fudge turn %d' % turn)

rootLogger = logging.getLogger()
handler = logging.StreamHandler()
rootFormatter = logging.Formatter('root - %(levelname)s: %(msg)s')
handler.setFormatter(rootFormatter)
rootLogger.addHandler(handler)
rootLogger.setLevel(logging.DEBUG)

do_logging(1)

extraLogger = logging.getLogger('extra')
extraHandler = logging.StreamHandler()
extraFormatter = logging.Formatter('extra - %(levelname)s: %(msg)s')
extraHandler.setFormatter(extraFormatter)
extraLogger.addHandler(extraHandler)
extraLogger.setLevel(logging.INFO)

do_logging(2)

Actual Output:

root - INFO: some info turn 1
root - DEBUG: this is debug fudge turn 1
extra - INFO: some info turn 2
root - INFO: some info turn 2

Output that I would like to have:

root - INFO: some info turn 1
root - DEBUG: this is debug fudge turn 1
extra - INFO: some info turn 2
root - INFO: some info turn 2
root - DEBUG: this is debug fudge turn 2

I suspect that a custom Filter would be helpful in this case, but I do not know how...

You could use robert's LevelFilter like this:

# Put the Filter on the Handler so only INFO and higher is handled
extraHandler.addFilter(LevelFilter(logging.INFO))

# Let the Logger process everything (so it can propagate records to root)
extraLogger.setLevel(logging.DEBUG)

import logging

class LevelFilter(logging.Filter):
    """
    https://stackoverflow.com/a/7447596/190597 (robert)
    """
    def __init__(self, level):
        self.level = level

    def filter(self, record):
        return record.levelno >= self.level

def do_logging(turn):
    logger = logging.getLogger('extra')
    logger.info('some info turn %d' % turn) 
    logger.debug('this is debug fudge turn %d' % turn)

rootLogger = logging.getLogger()
handler = logging.StreamHandler()
rootFormatter = logging.Formatter('root - %(levelname)s: %(msg)s')
handler.setFormatter(rootFormatter)
rootLogger.addHandler(handler)
rootLogger.setLevel(logging.DEBUG)
do_logging(1)

extraLogger = logging.getLogger('extra')
extraHandler = logging.StreamHandler()
extraFormatter = logging.Formatter('extra - %(levelname)s: %(msg)s')
extraHandler.setFormatter(extraFormatter)
extraLogger.addHandler(extraHandler)

# Put the Filter on the Handler so only INFO and higher is handled
extraHandler.addFilter(LevelFilter(logging.INFO))

# Handle everything (so it can propagate to root)
extraLogger.setLevel(logging.DEBUG)
do_logging(2)

propagate

If this attribute evaluates to true, events logged to this logger will be passed to the handlers of higher level (ancestor) loggers, in addition to any handlers attached to this logger. Messages are passed directly to the ancestor loggers' handlers - neither the level nor filters of the ancestor loggers in question are considered.

If this evaluates to false, logging messages are not passed to the handlers of ancestor loggers.

please visit official python site for detailed discussion regarding this.

Diabling the propagate message

import logging

handler = logging.StreamHandler()

parent = logging.getLogger("parent")
parent.addHandler(handler)
child = logging.getLogger("parent.child")
child.propagate = False

child.setLevel(logging.DEBUG)
child.addHandler(handler)

child.info("HELLO")

Output:

$ python3.10 propagate.py 
HELLO

Code without disabling the propagate message

import logging

handler = logging.StreamHandler()

parent = logging.getLogger("parent")
parent.addHandler(handler)
child = logging.getLogger("parent.child")
#child.propagate = False

child.setLevel(logging.DEBUG)
child.addHandler(handler)


child.info("HELLO")

Output:

$ python3.10 propagate.py 
HELLO
HELLO

记录器类中有一个名为“propagate”的方法似乎可以满足您的要求: http//docs.python.org/2/library/logging.html#logger-objects

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