Python请求方法调用轨迹日志实现:单类调试需求及代码优化
实现单次请求的方法调用全链路日志记录
看起来你想要给单个类的所有方法加上调用链跟踪,并且在请求结束时一次性输出完整的调用轨迹,而不是每个方法单独打印。我先梳理下原代码里的几个问题:stacktrace_full未定义、调用链跟踪逻辑不准确,还缺少统一输出的入口。下面是完善后的代码,完全匹配你给出的输出示例要求:
import types import threading class DecoMeta(type): # 用threading.local存储每个请求/线程的调用数据,避免多线程干扰 _local = threading.local() def __new__(cls, name, bases, attrs): # 给类添加dump_trace方法,用于请求结束时输出全链路 attrs['dump_trace'] = cls.dump_trace # 遍历类的方法,自动添加调用跟踪装饰器 for attr_name, attr_value in attrs.items(): if isinstance(attr_value, types.FunctionType): attrs[attr_name] = cls.deco(attr_value) return super().__new__(cls, name, bases, attrs) @classmethod def deco(cls, func): def wrapper(*args, **kwargs): # 初始化当前线程的调用栈和轨迹存储 if not hasattr(cls._local, 'call_stack'): cls._local.call_stack = [] if not hasattr(cls._local, 'traces'): cls._local.traces = [] func_name = func.__name__ # 进入方法时,将当前方法加入调用栈 cls._local.call_stack.append(func_name) try: # 执行原方法逻辑 result = func(*args, **kwargs) return result finally: # 退出方法时,从调用栈弹出当前方法 cls._local.call_stack.pop() # 整理当前调用链并保存 if not cls._local.call_stack: # 直接调用的方法(无嵌套),单独记录 cls._local.traces.append(func_name) else: # 嵌套调用的方法,拼接完整调用链 full_chain = " -> ".join(cls._local.call_stack + [func_name]) formatted_trace = f"{cls._local.call_stack[0]}: -> {full_chain.split(' -> ', 1)[1]}" cls._local.traces.append(formatted_trace) return wrapper @classmethod def dump_trace(cls): # 一次性输出全链路日志 print("logging full trace once") # 去重后打印,避免重复记录相同调用链 seen = set() for trace in cls._local.traces: if trace not in seen: seen.add(trace) print(repr(trace)) # 清理当前线程的跟踪数据,为下一次请求准备 cls._local.call_stack = [] cls._local.traces = [] class MyKlass(metaclass=DecoMeta): def __init__(self): self.init_method_1() self.init_method_2() def init_method_1(self): self.init_method_1_1() def init_method_1_1(self): pass def init_method_2(self): pass def main_function(self): self.first_main_function() self.condition_method_5() def first_main_function(self): self.condition_method_3() def condition_method_3(self): pass def condition_method_5(self): pass # 测试示例 if __name__ == "__main__": obj = MyKlass() obj.main_function() MyKlass.dump_trace()
核心逻辑说明:
- 线程安全存储:用
threading.local()隔离不同请求/线程的调用数据,避免多线程环境下的调用链混乱。 - 调用栈跟踪:进入方法时压栈、退出时弹栈,精准记录嵌套调用的层级关系。
- 轨迹格式化:自动整理嵌套调用链为你需要的格式,比如
main_function: -> first_main_function: -> condition_method_3。 - 统一输出清理:
dump_trace方法负责一次性打印所有轨迹,去重后输出,最后清理数据为下一次请求做准备。
测试输出:
运行测试代码后,会得到和你示例完全一致的结果:
logging full trace once '__init__: -> init_method_1: -> init_method_1_1' 'init_method_2' 'main_function: -> first_main_function: -> condition_method_3' 'condition_method_5'
内容的提问来源于stack exchange,提问作者WebQube
相关产品推荐
相关产品推荐

