К сожалению logging
использует объект кода функции для вывода имени. Вы можете обойти это, используя аргумент ключевого слова extra
, чтобы указать некоторые дополнительные атрибуты для записи, которые затем можно будет использовать при форматировании. Вы можете сделать что-то вроде:
logging.basicConfig(
level=logging.DEBUG,
format='%(real_func_name)20s - %(message)s',
)
...
logging.info(statement, extra={'real_func_name': func.__name__})
Единственным недостатком этого подхода является то, что вам приходится каждый раз вводить словарь extra
. Чтобы избежать этого, вы можете использовать собственный форматтер и переопределить его funcName
:
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
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('%(funcName)20s - %(message)s'))
logger.addHandler(handler)
def log_and_call(statement):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# set name_override to func.__name__
logger.info(statement, extra={'name_override': func.__name__})
return func(*args, **kwargs)
return wrapper
return decorator
@log_and_call("This should be logged by 'decorated_function'")
def decorated_function():
logger.info('I ran')
decorated_function()
Что делает то, что вы хотите:
% python logging_test.py
decorated_function - This should be logged by 'decorated_function'
decorated_function - I ran