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

Python实现无需传参的动态日志来源(文件名、行号等)记录

解决日志记录调用者文件名、函数名和行号的问题

你当前的日志输出显示的是log.py里log_message函数的位置,这是因为logger.info()是在log_message内部执行的,logging默认记录的是当前执行日志语句的栈帧信息。要让日志记录调用log_message的代码位置,有两种可靠方法:

方法一:使用Python 3.8+支持的stacklevel参数

这是最简单的官方解决方案,直接在调用logger.info时指定stacklevel=2,让logging跳过当前函数的栈帧,获取上一层调用者的信息:

修改log.py的代码:

import logging
logger = logging.getLogger(__name__)
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
logging.basicConfig(format=FORMAT)
logger.setLevel(logging.DEBUG)

def log_message(message):
    logger.info(message, stacklevel=2)  # 添加stacklevel参数

运行check.py后,输出会变为:
[check.py:4 - A() ] Error occurred

方法二:兼容Python 3.8以下版本(手动获取调用者栈信息)

如果你的Python版本低于3.8,可以通过inspect模块手动获取调用者的栈帧信息,再通过extra参数传递给日志记录器:

修改log.py的代码:

import logging
import inspect

logger = logging.getLogger(__name__)
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
logging.basicConfig(format=FORMAT)
logger.setLevel(logging.DEBUG)

def log_message(message):
    # 获取调用者的栈帧对象
    caller_frame = inspect.currentframe().f_back
    # 提取调用者的文件名、行号、函数名
    extra = {
        'filename': caller_frame.f_code.co_filename.split('/')[-1],
        'lineno': caller_frame.f_lineno,
        'funcName': caller_frame.f_code.co_name
    }
    logger.info(message, extra=extra)
    # 手动删除栈帧引用,避免内存泄漏
    del caller_frame

说明

  • stacklevel=2的含义是:跳过当前函数(log_message)的栈帧,追溯到调用它的那一层代码。
  • 手动获取栈帧时,记得删除栈帧引用,防止循环引用导致内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:25:18