问题现象

给几个接口函数加了计时装饰器,日志里打印的函数名全部一样,定位不到具体是哪个接口慢。

原因分析

装饰器返回的内层函数覆盖了原函数元信息,__name__ 和文档字符串都变成了 wrapper。判断时先分清是 Python 装饰器 functools.wraps 本身的配置问题,还是上游调用、运行环境带进来的差异;前者改配置就能收口,后者要沿着请求链路一层层往上找,处理顺序不能颠倒。先在出问题的机器上复现一次,把报错原文和发生时间记下来,再对着日志定位。

处理步骤

  1. 装饰器内层加 functools.wraps
  2. 保留原签名便于参数传递
  3. 需要更强签名时用 inspect.signature 适配

对应的命令或配置片段如下,可直接复制:

import functools, time
def timer(fn):
    @functools.wraps(fn)
    def inner(*a, **kw):
        t = time.time()
        try:
            return fn(*a, **kw)
        finally:
            print(fn.__name__, round(time.time() - t, 3))
    return inner

改动前把原配置备份一份,出问题时能马上回退,比现场找原因省时间。排查时把每一步的输出留下来,后面再遇到同类问题,对照日志就能判断是哪一层先出错的。

验证结果

日志里显示的是真实函数名,帮助文档和调试信息也与原函数一致。

作者 9823189