Python中如何在不冗余代码的情况下记录函数每一行执行日志?
解决方法
下面提供几种无需手动逐行添加日志的方案,既能记录代码执行路径,又不会让代码冗余:
方案1:自定义代码追踪装饰器
利用Python的sys.settrace机制,写一个装饰器自动记录函数内每一行执行的代码内容,无需修改原函数的业务逻辑:
import sys import logging from inspect import getsource logger = logging.getLogger(__name__) def trace_execution(func): def code_tracer(frame, event, arg): if event == 'line': # 获取当前执行行的代码文本 try: line_content = getsource(frame.f_code).splitlines()[frame.f_lineno - 1].strip() logger.info(f"Executing line: {line_content}") except (OSError, IndexError): # 处理无法获取源码的情况,记录行号和函数名 logger.info(f"Executing in {frame.f_code.co_name}, line {frame.f_lineno}") return code_tracer def wrapper(*args, **kwargs): # 保存原追踪函数,执行后恢复全局状态 original_tracer = sys.gettrace() sys.settrace(code_tracer) try: return func(*args, **kwargs) finally: sys.settrace(original_tracer) return wrapper # 给目标函数添加装饰器即可 @trace_execution def my_annoying_function(self): self._call_other_function() self.myvar = 5 i = 4 i = i + 5 if self.myothervar is True: self.call_other_function2() # ... 其他业务代码
这个装饰器会自动在每一行代码执行时,记录对应的代码文本(或行号信息),完全不需要在业务代码中插入日志语句。
方案2:使用标准库trace模块
Python内置的trace模块专门用于代码执行追踪,可直接利用它生成执行日志,无需手动编写追踪逻辑:
import sys import trace import logging logger = logging.getLogger(__name__) def run_with_execution_trace(func, *args, **kwargs): # 创建追踪器,关闭计数功能,开启行追踪 tracer = trace.Trace(count=False, trace=True) # 重定向trace的输出到logger original_stdout = sys.stdout class LoggerRedirector: def write(self, message): if message.strip(): logger.info(f"Trace: {message.strip()}") sys.stdout = LoggerRedirector() try: # 运行目标函数并追踪 tracer.runfunc(func, *args, **kwargs) finally: # 恢复原stdout sys.stdout = original_stdout # 使用方式:直接调用该函数执行目标函数 run_with_execution_trace(my_annoying_function, self)
trace模块会自动输出每一行执行的代码路径,我们通过重定向标准输出,把这些信息写入日志系统,无需修改原函数。
方案3:分支判断专用日志辅助函数
如果不需要记录每一行,只需要追踪if-else等分支的判断结果,可以写一个轻量的辅助函数,既记录判断逻辑又返回结果:
import logging logger = logging.getLogger(__name__) def log_and_return_condition(condition, description): condition_result = bool(condition) logger.info(f"Condition '{description}' evaluated to {condition_result}") return condition_result # 在目标函数中替换原判断语句 def my_annoying_function(self): self._call_other_function() self.myvar = 5 i = 4 i = i + 5 if log_and_return_condition(self.myothervar is True, "self.myothervar is True"): self.call_other_function2() # ... 其他分支判断
这种方式仅针对关键分支添加记录,代码冗余度极低,同时能明确追踪分支走向。
内容的提问来源于stack exchange,提问作者A. L
相关产品推荐
相关产品推荐

