'How get the called function to loggin with decorators?
I want to write to a log file some events. In order to do this I've used functions decorators to add the loggin code, and report the function called. But, the output is always the same function, the decorator function _decorador.
I'm using the %(funcName)s parameter in format logging.basicConfig
Output in example.log:
04/21/2014 09:32:41 AM DEBUG This message should go to the log file _decorador
04/21/2014 09:32:41 AM INFO So should this _decorador
04/21/2014 09:32:41 AM WARNING And this, too _decorador
04/21/2014 10:46:23 AM DEBUG This message should go to the log file (debug) _decorador
04/21/2014 10:46:23 AM INFO So should this (info) _decorador
04/21/2014 10:46:23 AM WARNING And this, too (warning) _decorador
Desired output in example.log:
04/21/2014 09:32:41 AM DEBUG This message should go to the log file mi_funcion
04/21/2014 09:32:41 AM INFO So should this mi_funcion
04/21/2014 09:32:41 AM WARNING And this, too mi_funcion
04/21/2014 10:46:23 AM DEBUG This message should go to the log file (debug) mi_funcion
04/21/2014 10:46:23 AM INFO So should this (info) mi_funcion
04/21/2014 10:46:23 AM WARNING And this, too (warning) mi_funcion
My code:
#!usr/bin/python3
# -*- coding: UTF-8 -*-
import logging
FORMAT = '%(asctime)s %(levelname)s %(message)s %(funcName)s'
logging.basicConfig(filename='example.log', level=logging.DEBUG, format=FORMAT, datefmt='%m/%d/%Y %I:%M:%S %p')
# Decorator function, writes in the log file.
def decorador(funcion):
def _decorador(*args, **kwargs):
funcion(*args, **kwargs)
logging.debug('This message should go to the log file (debug)')
logging.info('So should this (info)')
logging.warning('And this, too (warning)')
return _decorador
@decorador
def mi_funcion(arg1, arg2):
print("Code asset: %s; Registry number: s%" % (arg1, arg2))
mi_funcion("18560K", 12405)
Solution 1:[1]
You can extract the function name from the funcion object:
def decorador(funcion):
def _decorador(*args, **kwargs):
funcion(*args, **kwargs)
logging.debug('This message should go to the log file (debug) %s',
funcion.__name__)
# ...
return _decorador
I get this output after running the modified code:
cat example.log
04/21/2014 11:37:12 AM DEBUG This message should go to the log file (debug) mi_funcion
Solution 2:[2]
It's 2022 and this is still difficult.
Here's a complete example adapted from Using functools.wraps with a logging decorator
from inspect import getframeinfo, stack
import logging
from functools import wraps
class CustomFormatter(logging.Formatter):
"""Custom formatter, overrides funcName with value of name_override if it exists"""
def format(self, record):
if hasattr(record, 'name_override'):
record.funcName = record.name_override
if hasattr(record, 'file_override'):
record.filename = record.file_override
if hasattr(record, 'line_override'):
record.lineno= record.line_override
return super(CustomFormatter, self).format(record)
# setup logger and handler
logger = logging.getLogger(__file__)
handler = logging.StreamHandler()
logger.setLevel(logging.DEBUG)
handler.setLevel(logging.DEBUG)
handler.setFormatter(CustomFormatter('%(asctime)s - %(filename)s:%(lineno)s - %(funcName)s - %(levelname)s - %(message)s'))
logger.addHandler(handler)
def log_and_call(statement):
def decorator(func):
caller = getframeinfo(stack()[1][0])
@wraps(func)
def wrapper(*args, **kwargs):
# set name_override to func.__name__
logger.info(statement, extra={
'name_override': func.__name__,
'file_override': os.path.basename(caller.filename),
'line_override': caller.lineno
})
return func(*args, **kwargs)
return wrapper
return decorator
@log_and_call("This should be logged by 'decorated_function'")
def decorated_function(): # <- the logging in the wrapped function will point to/log this line for lineno.
logger.info('I ran')
decorated_function()
Defining the caller outside of the wrapper function will correctly get the calling function's (i.e. the wrapped function) filename and line number.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Tim |
