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

如何解决Python Logger日志重复输出的问题

解决Python自定义Logger日志重复输出问题

问题描述

我编写了一个带有不同级别格式化器的自定义Python Logger,输出的.txt文件格式正确,但每条日志语句都会重复。

原代码

import os
import sys
import time
import datetime
import logging

# 切换工作目录
os.chdir('C:\Git_Repo\pyautotest\AutoTest\OutputLogs')


def timeStamped(fname, fmt='%Y-%m-%d_%H.%M.%S - {fname}'):
    return datetime.datetime.now().strftime(fmt).format(fname=fname)

# 日志级别说明
# DEBUG: 详细诊断信息,仅排查问题时有用
# INFO: 确认系统正常运行
# WARNING: 出现意外情况或潜在问题,但系统仍可正常工作
# ERROR: 系统无法执行某些功能,问题较严重
# CRITICAL: 严重错误,程序可能无法继续运行


PrintLog = logging.getLogger(__name__)
PrintLog.setLevel(logging.DEBUG)


class MyFormatter(logging.Formatter):

    debug_fmt  = "%(levelname)s: %(asctime)s: %(pathname)s: Line %(lineno)s:  %(message)s"
    info_fmt = "%(levelname)s: %(asctime)s: %(message)s"
    error_fmt = "%(levelname)s: %(asctime)s: %(pathname)s: Line %(lineno)s:  ERROR - %(message)s"
    
    def __init__(self):
        super().__init__(fmt="%(levelno)d: %(msg)s", datefmt='%Y-%m-%d_%H.%M', style='%')  
    
    def format(self, record):
        # 保存原始格式
        format_orig = self._style._fmt

        # 根据日志级别切换格式
        if record.levelno == logging.DEBUG:
            self._style._fmt = MyFormatter.debug_fmt
        elif record.levelno == logging.INFO:
            self._style._fmt = MyFormatter.info_fmt
        elif record.levelno == logging.ERROR:
            self._style._fmt = MyFormatter.error_fmt

        # 执行格式化
        result = logging.Formatter.format(self, record)

        # 恢复原始格式
        self._style._fmt = format_orig
        return result

fmt = MyFormatter()
PrintLog.propagate = False

stream = logging.Formatter('%(message)s')

stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(stream)

debug_handler = logging.FileHandler(timeStamped('Test Log.txt'))
debug_handler.setFormatter(fmt)
            
info_handler = logging.FileHandler(timeStamped('Test Log.txt'))
info_handler.setFormatter(fmt)
  
PrintLog.addHandler(debug_handler)
PrintLog.addHandler(info_handler)
PrintLog.addHandler(stream_handler)

日志输出示例

INFO: 2023-11-20_11.07: Comencing Autotest.

INFO: 2023-11-20_11.07: Comencing Autotest.

INFO: 2023-11-20_11.07: Operating System = Windows

INFO: 2023-11-20_11.07: Operating System = Windows

DEBUG: 2023-11-20_11.07: C:\Git_Repo\pyautotest\AutoTest\Chris PyAuto Dev\new_test_menu.py: Line 48:  Quitting
DEBUG: 2023-11-20_11.07: C:\Git_Repo\pyautotest\AutoTest\Chris PyAuto Dev\new_test_menu.py: Line 48:  Quitting

解决方案

问题根源

你给同一个日志器添加了两个功能完全重复的FileHandler(debug_handler和info_handler),它们指向同一个日志文件、使用相同的格式化器。无论日志级别是INFO还是DEBUG,两个handler都会处理并写入文件,导致每条日志被输出两次。

修复方案

只保留一个FileHandler即可——你的自定义MyFormatter已经能根据日志级别自动切换输出格式,不需要为不同级别单独创建handler。

修改后的代码

import os
import sys
import time
import datetime
import logging

# 切换工作目录
os.chdir('C:\Git_Repo\pyautotest\AutoTest\OutputLogs')


def timeStamped(fname, fmt='%Y-%m-%d_%H.%M.%S - {fname}'):
    return datetime.datetime.now().strftime(fmt).format(fname=fname)

# 日志级别说明(可保留原注释内容)


PrintLog = logging.getLogger(__name__)
PrintLog.setLevel(logging.DEBUG)


class MyFormatter(logging.Formatter):

    debug_fmt  = "%(levelname)s: %(asctime)s: %(pathname)s: Line %(lineno)s:  %(message)s"
    info_fmt = "%(levelname)s: %(asctime)s: %(message)s"
    error_fmt = "%(levelname)s: %(asctime)s: %(pathname)s: Line %(lineno)s:  ERROR - %(message)s"
    
    def __init__(self):
        super().__init__(fmt="%(levelno)d: %(msg)s", datefmt='%Y-%m-%d_%H.%M', style='%')  
    
    def format(self, record):
        format_orig = self._style._fmt

        if record.levelno == logging.DEBUG:
            self._style._fmt = MyFormatter.debug_fmt
        elif record.levelno == logging.INFO:
            self._style._fmt = MyFormatter.info_fmt
        elif record.levelno == logging.ERROR:
            self._style._fmt = MyFormatter.error_fmt

        result = logging.Formatter.format(self, record)
        self._style._fmt = format_orig
        return result

fmt = MyFormatter()
PrintLog.propagate = False

stream = logging.Formatter('%(message)s')
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(stream)

# 仅保留一个FileHandler
file_handler = logging.FileHandler(timeStamped('Test Log.txt'))
file_handler.setFormatter(fmt)
  
PrintLog.addHandler(file_handler)
PrintLog.addHandler(stream_handler)

效果验证

修改后,每条日志只会被写入一次,同时依然保留不同级别对应的格式化效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:04:56