如何让Python日志记录函数调用方的文件名和行号
解决日志显示调用
track()的文件和行号问题 要让日志输出调用track函数的位置而非logging.info所在的位置,有两种实用方案:
方案1:利用Python 3.8+的stacklevel参数(推荐)
Python 3.8及以上版本的logging模块支持stacklevel参数,通过指定该参数跳过当前函数的栈帧,直接记录上层调用者的信息:
修改myutils.py中的track函数:
import logging def track(iterator, description: str): logging.info( "Very useful information about %s", description, stacklevel=2 # 跳过当前track函数,记录调用track的位置 ) # 原有逻辑示例 yield from iterator
在main.py中配置日志格式(确保包含文件名和行号):
import logging import myutils logging.basicConfig( format='%(filename)s:%(lineno)d %(message)s', level=logging.INFO ) # 测试代码 object1 = [1,2,3] object2 = [4,5,6] for item in myutils.track(object1, "first"): pass for item in myutils.track(object2, "second"): pass
运行后日志会输出:
main.py:11 Very useful information about first main.py:14 Very useful information about second
方案2:用inspect模块兼容旧Python版本
如果需要兼容Python 3.8以下版本,可以通过inspect模块手动获取调用栈信息:
修改myutils.py:
import logging import inspect def track(iterator, description: str): # 获取调用栈,index=1对应调用track的帧 caller_frame = inspect.stack()[1] # 提取文件名(只保留最后部分)和行号 caller_file = caller_frame.filename.split('/')[-1] caller_line = caller_frame.lineno # 通过extra参数传递调用者信息到日志 logging.info( "Very useful information about %s", description, extra={'caller_file': caller_file, 'caller_line': caller_line} ) # 手动删除栈帧引用,避免内存泄漏 del caller_frame # 原有逻辑示例 yield from iterator
在main.py中配置日志格式时,使用自定义的caller_file和caller_line字段:
import logging import myutils logging.basicConfig( format='%(caller_file)s:%(caller_line)d %(message)s', level=logging.INFO ) # 测试代码 object1 = [1,2,3] object2 = [4,5,6] for item in myutils.track(object1, "first"): pass for item in myutils.track(object2, "second"): pass
注意事项
- 方案1的
stacklevel参数是logging模块官方提供的简洁方案,优先推荐; - 方案2使用
inspect.stack()时,记得手动删除帧引用,避免长期运行导致内存泄漏; - 两种方案都无需完整回溯,仅获取调用
track的直接位置信息。
内容的提问来源于stack exchange,提问作者Jordi Torrents
相关产品推荐
相关产品推荐

