python - 如何让被调用的函数使用装饰器进行日志记录?

标签 python logging decorator python-decorators

我想将一些事件写入日志文件。为了做到这一点,我使用了函数装饰器来添加登录代码,并报告调用的函数。但是,输出始终是同一个函数,装饰器函数 _decorador

我正在使用格式为 logging.basicConfig 的 %(funcName)s 参数

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

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

我的代码:

#!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)

最佳答案

现在是 2022 年,这仍然很困难。

这是一个改编自 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()

wrapper 函数之外定义调用者将正确获取调用函数(即包装函数)的文件名和行号。

关于python - 如何让被调用的函数使用装饰器进行日志记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23194101/

相关文章:

python - 如果变量不在列表中 == False 返回空列表

logging - 在 Docker 应用程序中使用 Logback 更改动态日志级别

类级别变量上的 Python 装饰器作为反射的元数据?

python - 装饰器与继承

python - 如何在Redis中保存复杂的数据结构?

python - 在 Python 中对生成器进行索引和切片

java - 使用 log4j 创建带有日期的日志文件

java - Spring Boot : How to use custom logback. xml 取决于当前环境或 spring 配置文件

reactjs - 开 Jest : Unexpected token @ Decorator

python - 在 pandas 的列之间复制值