I’m trying to write a simple decorator that logs a given statement before calling the decorated function. The logged statements should both appear to come from the same function, which I thought was the purpose of functools.wraps().
Why does the following code:
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(funcName)20s - %(message)s')
from functools import wraps
def log_and_call(statement):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(statement)
return func(*args, **kwargs)
return wrapper
return decorator
@log_and_call("This should be logged by 'decorated_function'")
def decorated_function():
logging.info('I ran')
decorated_function()
result in log statements like:
wrapper - This should be logged by 'decorated_function'
decorated_function - I ran
I thought the call to wraps would rename wrapper with decorated_function’s name.
I’m using python 2.7.1.
Unfortunately
logginguses the function code object to infer the name. You could work around this by using theextrakeyword argument to specify some additional attributes for the record, which you could then use during formatting. You could do something like:The only downside to this approach is that you have to pass in the
extradictionary every time. To avoid that you could use a custom formatter and have it overridefuncName:Which does what you want: