You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

日志写入逻辑封装为函数后,如何让日志正确记录调用方的funcName字段

解决日志funcName字段识别错误的问题

你的问题根源在于Python的logging模块默认会记录直接调用日志方法(比如logger.info)的函数名,也就是你的LoggerWriter,而不是上层的调用者DoSomething。下面提供两种简单有效的解决方案:

方法一:通过inspect模块手动指定调用者函数名

这种方法直接在日志封装函数里获取上层调用者的函数名,通过extra参数传给日志记录方法,覆盖默认的funcName:

import logging
import inspect
logging.config.fileConfig('logging.ini', disable_existing_loggers=False)
logger = logging.getLogger(__name__)

def LoggerWriter(df, text):
    # 获取调用当前函数的上层栈帧,提取函数名
    caller_frame = inspect.currentframe().f_back
    caller_func_name = caller_frame.f_code.co_name
    
    # 传入extra参数覆盖默认的funcName
    logger.info(
        'Test: {}; Method: {}; Description: {}'.format(df['Test'], df['Method'], text),
        extra={'funcName': caller_func_name}
    )

class DoStuff:
    # 注意:实例方法需要添加self参数,否则会报错
    def DoSomething(self, df):
        LoggerWriter(df, 'Start Function')
        # 此处执行相关操作
        LoggerWriter(df, 'Finish Function')

说明:

  • inspect.currentframe().f_back 获取到调用LoggerWriter的栈帧对象
  • f_code.co_name 从栈帧中提取对应的函数名
  • extra参数会将自定义的funcName注入到日志记录中,覆盖默认值

如果你的日志封装函数可能被多层嵌套调用(比如A调用LoggerWriter,B调用A),可以用inspect.stack()获取更上层的调用者:

# 替换LoggerWriter中的函数名获取逻辑
caller_func_name = inspect.stack()[1].function

不过inspect.stack()的性能开销比currentframe()略高,高频调用场景下建议优先用第一种方式。

方法二:自定义JSON格式化器,统一修改funcName

如果不想在每个日志调用处手动处理,可以自定义JsonFormatter,在格式化阶段自动调整funcName:

from pythonjsonlogger.jsonlogger import JsonFormatter
import logging

class CustomJsonFormatter(JsonFormatter):
    def format(self, record):
        # 从栈信息中解析上层调用者的函数名
        if hasattr(record, 'stack_info') and record.stack_info:
            # 栈信息的第二行通常包含调用者的函数名
            caller_line = record.stack_info.split('\n')[1].strip()
            if 'in ' in caller_line:
                record.funcName = caller_line.split('in ')[-1]
        return super().format(record)

然后修改logging.ini中的formatter配置,指定自定义的格式化器:

[formatter_json]
class=your_module_name.CustomJsonFormatter  # 替换成你存放CustomJsonFormatter的模块名
format=%(asctime)s %(name)s %(funcName)s %(levelname)s %(message)s

同时需要确保日志记录时开启栈信息,比如在调用logger.info时添加stack_info=True,或者在配置中设置全局栈信息参数。

验证效果

使用第一种方法后,日志输出的funcName会变成DoSomething,完全符合你的期望:

{"asctime": "2021-05-30 14:58:31,796", "name": "__main__", "funcName": "DoSomething", "levelname": "INFO", "message": "Test: X; Method: dev; Description: Start Function."}

内容的提问来源于stack exchange,提问作者Keity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 18:02:29