Python3.11/3.12自定义日志级别调用方信息异常问题
解决Python 3.11+自定义日志级别调用方信息错误问题
问题根源在于Python 3.11对日志模块的栈帧遍历逻辑做了调整,你用lambda包装logger._log()的方式会额外增加一层栈帧,导致日志模块错误地将lambda所在的日志模块文件识别为调用位置,而非实际业务代码的调用点。
修复方案:显式指定stacklevel参数,跳过自定义方法的栈帧
Python 3.8+的日志模块支持stacklevel参数,用于告诉日志模块需要跳过多少层栈帧来定位实际调用位置。以下是两种可靠的实现方式:
方式1:自定义Logger类(推荐,更规范)
import logging class CustomLogger(logging.Logger): def custom(self, msg, *args, **kwargs): # stacklevel=2 跳过当前custom方法的栈帧,指向实际调用处 kwargs.setdefault('stacklevel', 2) # 使用公开的log方法替代私有_log,提升兼容性 self.log(25, msg, *args, **kwargs) # 注册自定义Logger类 logging.setLoggerClass(CustomLogger) logger = logging.getLogger(__name__) # 添加自定义级别名称 logging.addLevelName(25, 'CUSTOM') # 测试调用 def test_business_code(): logger.custom("自定义级别日志内容") test_business_code()
方式2:直接给Logger实例绑定自定义函数
如果不想自定义Logger类,也可以直接给现有Logger实例添加方法:
import logging logger = logging.getLogger(__name__) logging.addLevelName(25, 'CUSTOM') def custom_log(msg, *args, **kwargs): kwargs.setdefault('stacklevel', 2) logger.log(25, msg, *args, **kwargs) # 绑定到logger实例 logger.custom = custom_log
为什么原来的lambda方式失效?
Python 3.11+优化了日志模块获取调用方信息的逻辑,默认栈帧遍历的起始点更贴近底层。lambda作为匿名函数会额外生成一层栈帧,而旧代码没有指定stacklevel,导致日志模块停留在lambda所在的栈帧,最终显示日志模块内部的文件和lambda函数信息。
通过显式设置stacklevel=2,日志模块会跳过自定义方法/函数的栈帧,直接定位到业务代码中调用logger.custom()的位置,恢复正确的pathname、函数名和行号信息。
内容的提问来源于stack exchange,提问作者Maksim Leali
相关产品推荐
相关产品推荐

