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
相关产品推荐
相关产品推荐

