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

如何在自定义TimedRotatingFileHandler中获取日志器名称?

解决方案:在Handler中通过LogRecord获取日志器名称

要实现根据日志器模块名自动生成独立日志文件,核心是在Handler的emit()方法中,通过传入的LogRecord对象获取日志器名称——每个日志记录都会携带它所属日志器的name属性,这正是你通过logging.getLogger(__name__)传入的模块名。

以下是具体的自定义Handler实现,复用TimedRotatingFileHandler的旋转逻辑,同时自动为每个模块生成独立日志文件:

import logging.handlers
import os

class ModuleBasedTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    def __init__(self, log_dir, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False):
        # 用空字符串占位父类的filename参数,后续动态生成
        super().__init__('', when=when, interval=interval, backupCount=backupCount, encoding=encoding, delay=delay, utc=utc)
        self.log_dir = log_dir
        # 维护每个日志器对应的专属文件处理器
        self.logger_handlers = {}

    def _get_logger_file_path(self, logger_name):
        # 将模块名的点替换为下划线,避免路径分隔符问题,也可直接使用原模块名
        filename = f"{logger_name.replace('.', '_')}.log"
        return os.path.join(self.log_dir, filename)

    def emit(self, record):
        logger_name = record.name
        if logger_name not in self.logger_handlers:
            # 为当前日志器创建专属的TimedRotatingFileHandler
            file_path = self._get_logger_file_path(logger_name)
            # 自动创建日志目录(你已实现的逻辑可替换此处)
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            # 复用当前Handler的参数初始化专属处理器
            sub_handler = logging.handlers.TimedRotatingFileHandler(
                file_path,
                when=self.when,
                interval=self.interval,
                backupCount=self.backupCount,
                encoding=self.encoding,
                delay=self.delay,
                utc=self.utc
            )
            # 继承主Handler的格式器
            if self.formatter:
                sub_handler.setFormatter(self.formatter)
            self.logger_handlers[logger_name] = sub_handler
        # 用专属处理器处理当前日志记录
        self.logger_handlers[logger_name].emit(record)

    def close(self):
        # 关闭所有日志器的专属处理器
        for handler in self.logger_handlers.values():
            handler.close()
        super().close()

使用方式

只需要初始化一次自定义Handler,然后将其添加到任意模块的日志器中即可,无需为每个日志器单独创建Handler:

# 初始化自定义Handler,设置日志目录和旋转规则
log_dir = "./module_logs"
handler = ModuleBasedTimedRotatingFileHandler(log_dir, when='d', backupCount=7)
# 设置日志格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

# 不同模块的日志器共享同一个Handler
logger_a = logging.getLogger("module.a")
logger_a.addHandler(handler)
logger_a.setLevel(logging.INFO)

logger_b = logging.getLogger("module.b")
logger_b.addHandler(handler)
logger_b.setLevel(logging.INFO)

# 测试日志输出
logger_a.info("模块A的业务日志")
logger_b.info("模块B的业务日志")

原理说明

  1. 每次调用emit()处理日志时,从record.name拿到当前日志所属的模块名;
  2. 检查是否已为该模块创建专属的文件处理器,未创建则动态生成对应日志文件并初始化处理器;
  3. 复用TimedRotatingFileHandler的内置旋转逻辑,无需自己实现文件切割、备份的代码;
  4. 所有模块共享同一个自定义Handler实例,自动实现按模块分文件存储日志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 17:36:19