如何在自定义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的业务日志")
原理说明
- 每次调用
emit()处理日志时,从record.name拿到当前日志所属的模块名; - 检查是否已为该模块创建专属的文件处理器,未创建则动态生成对应日志文件并初始化处理器;
- 复用
TimedRotatingFileHandler的内置旋转逻辑,无需自己实现文件切割、备份的代码; - 所有模块共享同一个自定义Handler实例,自动实现按模块分文件存储日志。
内容的提问来源于stack exchange,提问作者rainer
相关产品推荐
相关产品推荐

