Reputation: 578
I want to avoid writing code like logger.debug(msg, extra=self.extra)
. So far I've tried to do this in two ways (extending Logger and decorators), but neither succeeded.
If I extend the Logger class and implement methods like debug as follows:
def debug(self, msg, *args, **kwargs):
self._update_kwargs(**kwargs)
super(ExtendedLogger, self).debug(msg, *args, **kwargs)
The module / function name / line number that are logged are not the call sites of ExtendedLogger.debug, but the call super(ExtendedLogger, self).debug(msg, *args, **kwargs)
; ie they're always the same values. I have the same issue if I try to implement something similar with decorators.
I understand this is due to the call to findCaller
in _log
in this file: https://github.com/python/cpython/blob/2.7/Lib/logging/init.py (R.1284). Is it possible to log this extra data without essentially copy-pasting the implementation of Logger and tweaking it slightly?
Upvotes: 2
Views: 646
Reputation: 60957
This seems to be the exact purpose for which LoggerAdapter
exists:
LoggerAdapter
instances are used to conveniently pass contextual information into logging calls.
You might not even need to subclass anything, just use LoggerAdapter
directly:
logger = logging.getLogger(__name__)
logger = logging.LoggerAdapter(logger, extra={'extra_key': 'extra_value'})
If you want to provide the extra values dynamically, you can easily just subclass LoggerAdapter
and override its process
method to add extra values to all logging methods.
This avoids needing to override all the level-oriented logging methods (debug
, info
, warning
, etc.) and also nicely side-steps the findCaller
issue at the same time.
Upvotes: 3