Documentation
Several examples in the Logging Cookbook page show that setting a log level per handler via logging.config.dictConfig() is supposed to limit that handler to that level and above, just like the root logger has a level:
AFAICT handlers don't actually allow filtering levels by setting a "level" field (tested with 3.12.9), and it must instead be done through a filter (similar to the one used in the first example).
The correct snippet for the first example would be something akin to the following:
LOGGER_CONFIG = '''
{
"version": 1,
"disable_existing_loggers": false,
"filters": {
"warnings_and_below": {
"()" : "__main__.filter_below",
"level": "WARNING"
},
"errors_and_above": {
"()" : "__main__.filter_above",
"level": "ERROR"
}
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"filters": ["warnings_and_below"],
"stream": "ext://sys.stdout"
},
"stderr": {
"class": "logging.StreamHandler",
"filters": ["errors_and_above"],
"stream": "ext://sys.stderr"
}
},
"root": {
"level": "DEBUG",
"handlers": [
"stdout",
"stderr"
]
}
}
'''
def filter_below(level):
level = getattr(logging, level)
def filter(record):
return record.levelno <= level
return filter
def filter_above(level):
level = getattr(logging, level)
def filter(record):
return record.levelno >= level
return filter
It took a while to figure that out as a beginner, but looking at logging.handlers made me doubt these examples.
Documentation
Several examples in the Logging Cookbook page show that setting a log level per handler via
logging.config.dictConfig()is supposed to limit that handler to that level and above, just like the root logger has a level:AFAICT handlers don't actually allow filtering levels by setting a "level" field (tested with 3.12.9), and it must instead be done through a filter (similar to the one used in the first example).
The correct snippet for the first example would be something akin to the following:
It took a while to figure that out as a beginner, but looking at
logging.handlersmade me doubt these examples.