Theemuts
Theemuts

Reputation: 578

Can I extend the Logger class without changing logged module name / function name / line number?

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

Answers (1)

Daniel Pryden
Daniel Pryden

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

Related Questions