Reading the documentation of Python's logging
library (for version 2.7) I came across the following:
Logger.debug(msg, *args, **kwargs)
[...] The second keyword argument is extra which can be used to pass a dictionary which is used to populate the
__dict__
of the LogRecord created for the logging event with user-defined attributes. These custom attributes can then be used as you like. For example, they could be incorporated into logged messages. [...] The keys in the dictionary passed in extra should not clash with the keys used by the logging system. [emph. mine]
So why does this constraint exist? In my opinion this removes flexibility from the library for no good reason (it is up to the developer to check which keys are built-in and which are not).
Imagine you want to write a decorator which logs function entry and exit:
def log_entry_exit(func):
def wrapper(*args, **kwargs):
logger.debug('Entry')
result = func(*args, **kwargs)
logger.debug('Exit')
return result
return wrapper
@log_entry_exit
def foo():
pass
Suppose you also want to log the name of the enclosing function:
format_string = '%(funcName)s: %(message)s'
Oops! This doesn't work. The output is:
>>> foo()
wrapper: Entry
wrapper: Exit
Of course the function name evaluates to wrapper
because that is the enclosing function. However this is not what I want. I want the function name of the decorated function to be printed. Therefore it would be very convenient to just modify my logging calls to:
logger.debug('<msg>', extra={'funcName': func.__name__})
However (as the documentation already points out) this doesn't work:
KeyError: "Attempt to overwrite 'funcName' in LogRecord"
Nevertheless this would be a very straightforward and light solution to the given problem.
So again, why is logging
preventing me from setting custom values for built-in attributes?