You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python中如何记录完整模块路径、类与函数名称?

如何在Python日志中记录完整的模块路径、类及函数名称

要实现你想要的日志输出格式(包含模块、类、函数的完整路径),默认的日志格式占位符(比如%(module)s%(funcName)s)没法直接满足需求——因为没有内置的类名字段。不过我们可以通过自定义日志格式器结合inspect模块来自动获取这些信息,不需要修改业务代码里的日志调用逻辑。

完整解决方案代码

import logging
import inspect

class CustomFormatter(logging.Formatter):
    def format(self, record):
        # 遍历调用栈,找到日志调用所在的上下文(跳过logging自身的帧)
        frame = inspect.currentframe()
        try:
            while frame:
                code_frame = frame.f_code
                # 检查当前帧是否属于类实例方法(有self变量)
                if "self" in frame.f_locals:
                    record.classname = frame.f_locals["self"].__class__.__name__
                    break
                # 检查是否属于类方法(有cls变量)
                elif "cls" in frame.f_locals:
                    record.classname = frame.f_locals["cls"].__name__
                    break
                # 向上移动到上一帧
                frame = frame.f_back
        finally:
            # 手动删除引用,避免循环引用导致内存泄漏
            del frame

        # 拼接完整路径:模块名.类名.函数名(如果没有类名则只保留模块.函数)
        if hasattr(record, "classname"):
            record.full_qualname = f"{record.module}.{record.classname}.{record.funcName}"
        else:
            record.full_qualname = f"{record.module}.{record.funcName}"
        
        # 调用父类的format方法完成最终格式化
        return super().format(record)

# 配置日志系统
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# 创建控制台处理器并绑定自定义格式器
console_handler = logging.StreamHandler()
formatter = CustomFormatter("%(levelname)s | %(full_qualname)s | %(message)s")
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)

# 测试代码
class MyClass:
    def my_function(self):
        logger.debug('msg')
    
    @classmethod
    def my_class_method(cls):
        logger.debug('class method msg')

if __name__ == "__main__":
    obj = MyClass()
    obj.my_function()
    MyClass.my_class_method()

代码说明

  1. 自定义Formatter:重写format方法,通过inspect.currentframe()遍历调用栈,找到包含self(实例方法)或cls(类方法)的帧,从而提取类名。
  2. 拼接完整路径:将模块名(record.module)、类名、函数名(record.funcName)拼接成full_qualname字段,供格式字符串使用。
  3. 避免内存泄漏:遍历完成后手动删除帧引用,防止循环引用导致的内存问题。

输出效果

运行上述代码后,会得到如下输出:

DEBUG | my_module.MyClass.my_function | msg
DEBUG | my_module.MyClass.my_class_method | class method msg

(注:如果你的模块在my_package下,输出会自动变成my_package.my_module.MyClass.my_function,因为record.module会自动识别当前模块的名称)

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

火山引擎 最新活动