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

如何让Python所有日志调用继承调用模块的名称?

问题描述

我正在构建一系列相互关联的应用,基类定义在base.py文件中,子类定义在class.py中,代码示例如下:

# base.py
logger = logging.getLogger(__name__)
class Base():
  def __init__(self):
    logger.info("Parent success")

# class.py
logger = logging.getLogger(__name__)
class Child(Base):
  def __init__(self):
    super().__init__()
    logger.info("Child success")

# main.py
this = Child()

需求:希望所有日志都显示调用类的模块名称(即父类和子类的日志都显示来自main.py),且不能通过__init__参数传递logger,求更优雅的解决方案。

优雅解决方案

方法1:自定义日志过滤器改写模块名

无需修改原有类的代码,只需在入口模块配置一个日志过滤器,自动将日志记录的模块名替换为实际调用者的模块名。

# 自定义过滤器
import logging
import inspect

class CallerModuleFilter(logging.Filter):
    def filter(self, record):
        try:
            # 回溯调用栈,跳过日志内部帧,定位业务代码调用帧
            for frame_info in inspect.stack()[1:]:
                frame = frame_info[0]
                module = inspect.getmodule(frame)
                if module and not module.__name__.startswith("logging"):
                    record.name = module.__name__
                    record.module = module.__name__
                    break
        except Exception:
            pass
        return True

在入口模块(比如main.py)中配置日志:

# main.py
import logging
from class import Child

if __name__ == "__main__":
    # 配置日志并添加过滤器
    logging.basicConfig(format="%(name)s - %(levelname)s - %(message)s")
    root_logger = logging.getLogger()
    root_logger.addFilter(CallerModuleFilter())
    
    this = Child()

这种方式对原有代码侵入性极低,适合多模块复用的场景,所有日志都会自动显示调用者的模块名称。

方法2:通过调用栈动态获取调用者的Logger

在基类和子类的__init__中,利用inspect模块获取创建实例的调用者模块,并使用该模块的Logger。

修改base.py:

# base.py
import logging
import inspect

class Base():
    def __init__(self):
        # 获取调用栈中创建实例的帧
        caller_frame = inspect.stack()[1]
        caller_module = inspect.getmodule(caller_frame[0])
        self.logger = logging.getLogger(caller_module.__name__)
        self.logger.info("Parent success")

修改class.py:

# class.py
import logging
import inspect
from base import Base

class Child(Base):
    def __init__(self):
        super().__init__()
        caller_frame = inspect.stack()[1]
        caller_module = inspect.getmodule(caller_frame[0])
        self.logger = logging.getLogger(caller_module.__name__)
        self.logger.info("Child success")

这种方式直接在类内部获取调用者的Logger,逻辑直观,但inspect.stack()会有轻微性能开销,高并发场景需权衡。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:14:55