如何在应用日志中记录嵌套函数调用的函数名称?
如何在Python日志中记录函数调用链信息
当你用%(funcName)只能拿到当前执行日志代码的函数名,要获取func_A→func_B→func_C这类调用链,可以用以下两种实用方法:
方法一:手动调用inspect模块获取调用栈
直接借助Python的inspect模块遍历调用栈,提取各层级的函数名组装成调用链:
import inspect import logging def get_call_chain(): # 跳过当前函数和日志调用的层级(索引需根据实际代码调整) stack_frames = inspect.stack()[2:] # 反转栈顺序,得到从调用起点到当前函数的链(A→B→C) return "→".join(frame.function for frame in reversed(stack_frames)) # 配置日志格式 logging.basicConfig( format="%(asctime)s - %(levelname)s - 调用链:%(message)s", level=logging.INFO ) def func_C(): chain = get_call_chain() logging.info(f"{chain} | 执行func_C") def func_B(): func_C() def func_A(): func_B() func_A()
运行后日志会输出类似:2024-05-20 10:00:00,000 - INFO - 调用链:func_A→func_B→func_C | 执行func_C
注意:inspect.stack()的索引需要根据实际代码调整——比如如果你的日志封装了多层函数,可能需要增大跳过的索引数,确保只拿到业务代码的调用栈。
方法二:自定义日志过滤器自动注入调用链
通过自定义日志过滤器,让调用链自动附加到每条日志记录中,无需手动调用:
import inspect import logging class CallChainFilter(logging.Filter): def filter(self, record): # 跳过日志模块内部的调用层级(索引需调试确认) stack_frames = inspect.stack()[5:] record.call_chain = "→".join(frame.function for frame in reversed(stack_frames)) return True # 初始化日志器 logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # 配置处理器和格式化器 handler = logging.StreamHandler() formatter = logging.Formatter( "%(asctime)s - %(levelname)s - 调用链:%(call_chain)s - %(message)s" ) handler.setFormatter(formatter) handler.addFilter(CallChainFilter()) logger.addHandler(handler) def func_C(): logger.info("执行func_C") def func_B(): func_C() def func_A(): func_B() func_A()
这种方式更优雅,所有日志都会自动带上调用链,适合大型项目使用。
注意事项
- 性能影响:
inspect.stack()会遍历调用栈,对高并发场景有一定性能损耗,建议只在DEBUG或INFO级别启用,生产环境可根据需求关闭。 - 索引调整:不同的日志封装层级会导致
inspect.stack()的有效索引不同,需要实际调试确定跳过的层数。
内容的提问来源于stack exchange,提问作者Shibu
相关产品推荐
相关产品推荐

