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

Python多日志处理器结合ANSI颜色码出现异常问题排查

Python日志配置:解决控制台与文件日志的ANSI颜色区分问题

问题概述

需要实现控制台日志按级别显示不同ANSI颜色,同时日志文件输出无ANSI字符的功能,但配置过程中出现以下异常:

  • 修正if handler.name != "file_handler"的逻辑错误后,控制台输出全为红色,日志文件反而显示颜色(PyCharm中)
  • 直接设置带颜色的COLORS时,控制台颜色显示正常,但日志文件残留ANSI字符
  • INFO级别日志有时显示为白色而非绿色

核心问题分析

  1. Formatter实例共享导致逻辑冲突
    原代码中同一个Formatter实例被控制台和文件处理器共享,且在format方法中遍历所有日志处理器,最后一个处理器的设置会覆盖COLORS变量,导致所有日志都使用最后一次设置的颜色规则,完全违背了区分处理器的初衷。

  2. 颜色重置冗余
    INFO级别的格式字符串中包含两个COLORS["RESET"],第一个在INFO文字后就重置了颜色,导致后续的日志消息回到终端默认色(白色)。

  3. PyCharm的日志文件渲染特性
    PyCharm会自动解析日志文件中的ANSI转义码并渲染为颜色,而非显示原始字符。当代码错误导致文件输出带ANSI码时,就会出现日志文件显示颜色的“异常”,这是IDE的特性而非代码输出的问题。

正确解决方案

为每个日志处理器分配独立的Formatter实例,通过参数控制是否启用颜色,彻底避免共享实例的逻辑冲突:

import logging

class ColoredFormatter(logging.Formatter):
    def __init__(self, use_color=True, **kwargs):
        super().__init__(**kwargs)
        self.use_color = use_color
        # 按日志级别映射对应颜色
        self.level_colors = {
            logging.DEBUG: '\x1b[34m',      # 蓝色
            logging.INFO: '\x1b[32m',       # 绿色
            logging.WARNING: '\x1b[33m',    # 黄色
            logging.ERROR: '\x1b[31m',      # 红色
            logging.CRITICAL: '\x1b[31;1m'  # 加粗红色
        }
        self.reset_code = '\x1b[0m' if use_color else ''

    def format(self, record):
        # 先获取基础格式化后的日志内容
        base_msg = super().format(record)
        if self.use_color:
            # 为对应级别添加颜色包裹
            color = self.level_colors.get(record.levelno, '')
            return f"{color}{base_msg}{self.reset_code}"
        return base_msg

def setup_logging():
    # 初始化根日志器
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)
    root_logger.handlers.clear()  # 清除默认处理器

    # 文件处理器:禁用颜色,输出纯净日志
    file_handler = logging.FileHandler("log.log")
    file_formatter = ColoredFormatter(
        use_color=False,
        fmt="%(levelname)s - %(message)s"
    )
    file_handler.setFormatter(file_formatter)

    # 控制台处理器:启用颜色,按级别区分显示
    console_handler = logging.StreamHandler()
    console_formatter = ColoredFormatter(
        use_color=True,
        fmt="%(levelname)s - %(message)s"
    )
    console_handler.setFormatter(console_formatter)

    # 添加处理器到根日志器
    root_logger.addHandler(file_handler)
    root_logger.addHandler(console_handler)

if __name__ == "__main__":
    setup_logging()
    logging.debug("This is a debug message")
    logging.info("This is an info message")
    logging.warning("This is a warning message")
    logging.error("This is an error message")
    logging.critical("This is a critical message")

方案优势

  • 隔离处理器逻辑:每个处理器使用独立的Formatter实例,颜色控制互不干扰
  • 简洁的颜色管理:按级别映射颜色,避免冗余的颜色变量定义
  • 解决重置问题:仅在日志内容末尾添加一次颜色重置,确保完整的颜色渲染

额外说明

  • 若需要自定义更复杂的格式(如添加日志名称、行号等),只需修改fmt参数即可,例如:fmt="%(name)s - %(levelname)s - %(message)s"
  • PyCharm中若想查看日志文件的原始ANSI字符,可右键文件选择「Open in > Plain Text」

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:53:20