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

Python自定义logging子类自定义级别LogRecord属性显示异常如何修复

问题原因

logging模块默认生成LogRecord时,只会跳过logging包内的栈帧,你自定义的verbose、trace方法属于自定义类代码,不在logging包范围内,因此log方法会把这两个方法的调用位置识别为日志打印触发点,最终输出的就是自定义日志类的文件和方法名。

修复方案

方案1:使用stacklevel参数(Python 3.8+ 推荐)

Python 3.8及以上版本的Logger.log()方法支持stacklevel参数,用来指定需要向上跳过的栈层数,你的自定义方法额外多了1层调用,设置stacklevel=2即可。

import logging

# 未注册自定义级别需要先添加以下4行
logging.VERBOSE = 15
logging.TRACE = 5
logging.addLevelName(logging.VERBOSE, "VERBOSE")
logging.addLevelName(logging.TRACE, "TRACE")

class DefaultLogger(logging.Logger):

    def __init__(self, name):
        super().__init__(name)
        self.propagate = True
        self.setLevel(logging.NOTSET)

    def verbose(self, msg, *args, **kwargs):
        # 未显式指定stacklevel时默认多跳过1层当前方法的栈帧
        if 'stacklevel' not in kwargs:
            kwargs['stacklevel'] = 2
        self.log(logging.VERBOSE, msg, *args, **kwargs)

    def trace(self, msg, *args, **kwargs):
        if 'stacklevel' not in kwargs:
            kwargs['stacklevel'] = 2
        self.log(logging.TRACE, msg, *args, **kwargs)

方案2:兼容Python 3.8以下版本

如果需要兼容旧版本Python,可以重写findCaller方法,把自定义日志类所在的文件名加入跳过列表,查找调用栈时会自动跳过该文件的栈帧:

import logging
import os

# 注册自定义级别
logging.VERBOSE = 15
logging.TRACE = 5
logging.addLevelName(logging.VERBOSE, "VERBOSE")
logging.addLevelName(logging.TRACE, "TRACE")

class DefaultLogger(logging.Logger):
    # 获取当前文件绝对路径,用于标记需要跳过的栈帧
    _srcfile = os.path.normcase(__file__)

    def __init__(self, name):
        super().__init__(name)
        self.propagate = True
        self.setLevel(logging.NOTSET)

    def findCaller(self, stack_info=False, stacklevel=1):
        f = logging.currentframe()
        # 跳过所有当前文件内的栈帧
        while f:
            co = f.f_code
            filename = os.path.normcase(co.co_filename)
            if filename == self._srcfile:
                f = f.f_back
                continue
            sinfo = None
            if stack_info:
                import traceback
                sinfo = '\n'.join(traceback.format_stack())
            return (co.co_filename, f.f_lineno, co.co_name, sinfo)
        return ("(unknown file)", 0, "(unknown function)", None)

    def verbose(self, msg, *args, **kwargs):
        self.log(logging.VERBOSE, msg, *args, **kwargs)

    def trace(self, msg, *args, **kwargs):
        self.log(logging.TRACE, msg, *args, **kwargs)

修改完成后调用自定义级别方法,输出的filename、funcName就会显示实际业务代码的调用位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:24:03