Little fix to excellent Denis's solution.
Logging name system based on hierarchical structure:
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
.
For example, when you setLevel() for some logger, this level will be also applied to child loggers. That's why you might want your formatter will be used for logger and it's child loggers too. For example, 'one.two'
formatter should also be applied to 'one.two.three'
logger (if no formatter for 'one.two.three'
set). Here's version of DispatchingFormatter that do job (Python 3 code):
class DispatchingFormatter:
"""Dispatch formatter for logger and it's sub logger."""
def __init__(self, formatters, default_formatter):
self._formatters = formatters
self._default_formatter = default_formatter
def format(self, record):
# Search from record's logger up to it's parents:
logger = logging.getLogger(record.name)
while logger:
# Check if suitable formatter for current logger exists:
if logger.name in self._formatters:
formatter = self._formatters[logger.name]
break
else:
logger = logger.parent
else:
# If no formatter found, just use default:
formatter = self._default_formatter
return formatter.format(record)
Example:
handler = logging.StreamHandler()
handler.setFormatter(DispatchingFormatter({
'one': logging.Formatter('%(message)s -> one'),
'one.two': logging.Formatter('%(message)s -> one.two'),
},
logging.Formatter('%(message)s -> <default>'),
))
logging.getLogger().addHandler(handler)
print('Logger used -> formatter used:')
logging.getLogger('one').error('one')
logging.getLogger('one.two').error('one.two')
logging.getLogger('one.two.three').error('one.two.three') # parent formatter 'one.two' will be used here
logging.getLogger('other').error('other')
# OUTPUT:
# Logger used -> formatter used:
# one -> one
# one.two -> one.two
# one.two.three -> one.two
# other -> <default>