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

Python logging日志重复问题:自定义日志类多实例导致重复记录

这是Python logging模块里非常常见的一个坑——全局Logger实例被重复添加Handler导致的日志重复输出,我来给你拆解清楚:

为什么会出现重复日志?

Python的logging模块中,通过logging.getLogger(name)获取的Logger实例是全局共享的——只要name参数相同,每次调用都会返回同一个对象。

假设你的MyLog类是这样写的(这是最容易踩坑的写法):

import logging

class MyLog:
    def __init__(self):
        # 获取全局共享的Logger实例
        self.logger = logging.getLogger("my_custom_logger")
        self.logger.setLevel(logging.DEBUG)
        
        # 每次实例化都添加控制台处理器
        stream_handler = logging.StreamHandler()
        self.logger.addHandler(stream_handler)
        
        # 每次实例化都添加文件处理器
        file_handler = logging.FileHandler("app.log")
        self.logger.addHandler(file_handler)
        
        # 省略格式器配置...

那么:

  • 当TestA实例化MyLog时,这个Logger会被添加2个Handler(控制台+文件),此时调用日志方法会正常输出1条记录;
  • 当TestB实例化MyLog时,又会给同一个Logger再添加2个Handler,此时每条日志会被2组Handler分别处理,所以你看到2条重复记录;
  • 到TestC实例化时,Logger累计了3组Handler,每条日志会被处理3次,自然就出现3条重复。

简单说:每多实例化一次MyLog,就给全局Logger多塞一组Handler,后续日志会被所有已添加的Handler重复输出。

怎么解决这个问题?

我给你三个靠谱的解决方案,按推荐优先级排序:

方案1:添加Handler前先检查,避免重复添加

在初始化Logger时,先判断是否已经存在对应类型的Handler,只有不存在时才添加:

import logging

class MyLog:
    def __init__(self):
        self.logger = logging.getLogger("my_custom_logger")
        self.logger.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        
        # 检查是否已有控制台Handler,没有才添加
        has_stream_handler = any(isinstance(hdlr, logging.StreamHandler) for hdlr in self.logger.handlers)
        if not has_stream_handler:
            stream_handler = logging.StreamHandler()
            stream_handler.setFormatter(formatter)
            self.logger.addHandler(stream_handler)
        
        # 检查是否已有文件Handler,没有才添加
        has_file_handler = any(isinstance(hdlr, logging.FileHandler) for hdlr in self.logger.handlers)
        if not has_file_handler:
            file_handler = logging.FileHandler("app.log")
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)
    
    # 日志方法示例
    def debug(self, msg):
        self.logger.debug(msg)
    
    def info(self, msg):
        self.logger.info(msg)

方案2:用单例模式确保MyLog只实例化一次

让MyLog类成为单例,整个程序生命周期中只有一个实例,这样Handler只会被添加一次:

import logging

class MyLog:
    _instance = None  # 保存单例实例

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            # 第一次实例化时才初始化Logger和Handler
            cls._instance = super().__new__(cls, *args, **kwargs)
            cls._instance.logger = logging.getLogger("my_custom_logger")
            cls._instance.logger.setLevel(logging.DEBUG)
            
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            stream_handler = logging.StreamHandler()
            stream_handler.setFormatter(formatter)
            cls._instance.logger.addHandler(stream_handler)
            
            file_handler = logging.FileHandler("app.log")
            file_handler.setFormatter(formatter)
            cls._instance.logger.addHandler(file_handler)
        return cls._instance
    
    # 日志方法示例
    def debug(self, msg):
        self.logger.debug(msg)

方案3:初始化前清空已有Handler(谨慎使用)

如果确定这个Logger只会被MyLog使用,可以在初始化时先清空所有Handler,再重新添加:

import logging

class MyLog:
    def __init__(self):
        self.logger = logging.getLogger("my_custom_logger")
        self.logger.setLevel(logging.DEBUG)
        
        # 先清空所有已有Handler
        self.logger.handlers.clear()
        
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        stream_handler = logging.StreamHandler()
        stream_handler.setFormatter(formatter)
        self.logger.addHandler(stream_handler)
        
        file_handler = logging.FileHandler("app.log")
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)

⚠️ 注意:这个方案会清除该Logger的所有Handler,如果其他代码也在使用同一个Logger,会导致它们的日志配置失效,所以只适合完全由MyLog管控Logger的场景。

怎么验证问题是否解决?

你可以在MyLog的__init__方法里加一行打印,看看每次实例化后Logger的Handler数量:

print(f"当前Logger的Handler数量:{len(self.logger.handlers)}")

如果每次实例化后数量不再增加,就说明问题已经解决了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:35:30