Python多日志处理器结合ANSI颜色码出现异常问题排查
Python日志配置:解决控制台与文件日志的ANSI颜色区分问题
问题概述
需要实现控制台日志按级别显示不同ANSI颜色,同时日志文件输出无ANSI字符的功能,但配置过程中出现以下异常:
- 修正
if handler.name != "file_handler"的逻辑错误后,控制台输出全为红色,日志文件反而显示颜色(PyCharm中) - 直接设置带颜色的
COLORS时,控制台颜色显示正常,但日志文件残留ANSI字符 - INFO级别日志有时显示为白色而非绿色
核心问题分析
Formatter实例共享导致逻辑冲突
原代码中同一个Formatter实例被控制台和文件处理器共享,且在format方法中遍历所有日志处理器,最后一个处理器的设置会覆盖COLORS变量,导致所有日志都使用最后一次设置的颜色规则,完全违背了区分处理器的初衷。颜色重置冗余
INFO级别的格式字符串中包含两个COLORS["RESET"],第一个在INFO文字后就重置了颜色,导致后续的日志消息回到终端默认色(白色)。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
相关产品推荐
相关产品推荐

