如何用logging的TimedRotatingFileHandler生成.log格式的日志文件
如何让TimedRotatingFileHandler生成
file_name.日期.log格式的日志 完全可以实现这个需求!默认的TimedRotatingFileHandler确实会把时间后缀追加在原文件的扩展名之后,导致生成类似file_name.log.2019-10-09的文件,但我们可以通过继承并重写它的核心方法,自定义日志文件的命名逻辑。
核心思路
默认的轮转逻辑是直接把时间后缀加在原文件名末尾,我们需要拆分原文件名的“主名称”和“扩展名”,把时间后缀插入到两者之间,再重新拼接成目标文件名。
自定义处理器实现
下面是一个完整的自定义处理器代码,重写了doRollover方法(负责日志轮转的核心逻辑):
import logging from logging.handlers import TimedRotatingFileHandler import os import time class CustomTimedRotatingFileHandler(TimedRotatingFileHandler): def doRollover(self): # 关闭当前打开的日志流 if self.stream: self.stream.close() self.stream = None # 计算轮转的时间戳和对应的时间元组 currentTime = int(time.time()) dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) dstThen = timeTuple[-1] # 处理夏令时变化的情况 if dstNow != dstThen: addend = 3600 if dstNow else -3600 timeTuple = time.localtime(t + addend) # 拆分原文件名的主名称和扩展名,拼接成目标格式 base_dir, base_name = os.path.split(self.baseFilename) name, ext = os.path.splitext(base_name) # 这里按需求生成文件名:主名称.时间后缀.扩展名 dfn = os.path.join(base_dir, f"{name}.{time.strftime(self.suffix, timeTuple)}{ext}") # 如果目标文件已存在,先删除 if os.path.exists(dfn): os.remove(dfn) # 重命名当前日志文件到目标路径 os.rename(self.baseFilename, dfn) # 清理超过备份数量的旧日志(保持默认逻辑) if self.backupCount > 0: for s in self.getFilesToDelete(): os.remove(s) # 重新打开新的日志文件 self.mode = 'a' self.stream = self._open() # 计算下一次轮转的时间 newRolloverAt = self.computeRollover(currentTime) while newRolloverAt <= currentTime: newRolloverAt += self.interval # 再次处理夏令时对轮转时间的影响 if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: addend = -3600 if not dstNow else 3600 newRolloverAt += addend self.rolloverAt = newRolloverAt
使用自定义处理器
接下来就可以像使用普通TimedRotatingFileHandler一样使用这个自定义类了:
# 初始化日志记录器 logger = logging.getLogger("my_app_logger") logger.setLevel(logging.INFO) # 配置自定义处理器:按天轮转,保留7天日志 handler = CustomTimedRotatingFileHandler( filename="app.log", when="D", # 轮转周期:D=天,H=小时,M=分钟等 interval=1, backupCount=7, encoding="utf-8" ) # 设置日志格式 log_formatter = logging.Formatter( "%(asctime)s - %(levelname)s - %(message)s" ) handler.setFormatter(log_formatter) # 将处理器添加到日志记录器 logger.addHandler(handler) # 测试输出日志 logger.info("这是一条测试日志,验证自定义轮转格式")
注意事项
- 如果你需要按小时/分钟轮转,记得调整
when参数和对应的suffix格式(比如when="H"时,suffix="%Y-%m-%d_%H",生成app.2019-10-09_14.log)。 - 代码中保留了默认的夏令时处理逻辑,确保时间轮转的准确性。
- 如果不需要备份日志,可以将
backupCount设为0。
内容的提问来源于stack exchange,提问作者Michał Zawadzki




