You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让工具函数的日志显示为来自其调用方而非自身?

解决方案

要让工具函数里的日志显示调用方的module/funcName/lineno,核心是让日志模块跳过工具函数本身的栈帧,直接抓取上层调用者的信息。以下是几种实用方法:

方法一:用装饰器批量处理(符合你想要的@logAsCaller需求)

这个装饰器会临时修改日志的调用栈检测逻辑,让所有被装饰的工具函数输出日志时自动指向调用方:

import logging
import functools

def log_as_caller(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 保存原始的findCaller方法
        original_find_caller = logging.Logger.findCaller
        
        def modified_find_caller(self, stack_info=False, stacklevel=1):
            # 多跳一层栈帧,跳过当前工具函数
            return original_find_caller(self, stack_info, stacklevel + 1)
        
        # 替换方法并执行原函数
        logging.Logger.findCaller = modified_find_caller
        try:
            return func(*args, **kwargs)
        finally:
            # 恢复原方法,避免影响其他日志
            logging.Logger.findCaller = original_find_caller
    return wrapper

使用示例

# 给工具函数加上装饰器
@log_as_caller
def my_helper_fn():
    logging.warning("这条日志会显示调用方的信息")

def main():
    my_helper_fn()  # 日志里的funcName会是main,而非my_helper_fn

if __name__ == "__main__":
    logformat = '%(asctime)s %(levelname)s %(module)s:%(funcName)s:%(lineno)d - %(message)s'
    logging.basicConfig(format=logformat, level=logging.WARNING)
    main()

方法二:自定义Logger全局生效

如果所有工具函数都需要这个特性,可以自定义Logger类,重写findCaller方法让它默认跳过一层栈帧:

import logging

class CallerLogger(logging.Logger):
    def findCaller(self, stack_info=False, stacklevel=1):
        # 强制多跳一层,直接抓取调用方信息
        return super().findCaller(stack_info, stacklevel + 1)

# 替换默认的Logger类
logging.setLoggerClass(CallerLogger)

# 初始化日志
logformat = '%(asctime)s %(levelname)s %(module)s:%(funcName)s:%(lineno)d - %(message)s'
logging.basicConfig(format=logformat, level=logging.WARNING)

# 工具函数直接用logging即可
def my_helper_fn():
    logging.warning("这条日志会显示调用方的信息")

def main():
    my_helper_fn()

if __name__ == "__main__":
    main()

方法三:手动指定stacklevel(最简单)

Python 3.8+的日志方法支持stacklevel参数,直接给日志调用加stacklevel=2,就能跳过当前工具函数的栈帧:

def my_helper_fn():
    # stacklevel=2表示跳过当前函数,抓取调用方的栈信息
    logging.warning("这条日志会显示调用方的信息", stacklevel=2)

def main():
    my_helper_fn()

if __name__ == "__main__":
    logformat = '%(asctime)s %(levelname)s %(module)s:%(funcName)s:%(lineno)d - %(message)s'
    logging.basicConfig(format=logformat, level=logging.WARNING)
    main()

内容的提问来源于stack exchange,提问作者user2722968

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:20:29