TimedRotatingFileHandler日志未按天切分,主因是when='D'未配interval=1、backupCount=0禁用归档,或程序运行不足24小时;它基于上次滚动时间+24小时触发,非固定零点切分。

TimedRotatingFileHandler 为什么日志没按天切分?
常见现象是日志文件一直写入 app.log,第二天也没生成 app.log.2024-06-15 这类带日期后缀的归档文件。根本原因通常是:when='D' 没配对 interval=1,或 backupCount 被设为 0(禁用归档),又或者程序没运行满 24 小时——它不是“每天零点强制切”,而是“距上次滚动满 24 小时才触发”。
-
when='D'表示按日滚动,必须搭配interval=1(单位由when决定) - 首次启动时,handler 会读取日志文件的最后修改时间作为“上一次滚动时间”,若文件是手动创建的,mtime 可能不准,建议让 handler 自己创建日志文件
- Windows 下注意:文件系统可能缓存 mtime,导致次日首次写入不触发滚动;可加
delay=True避免提前 open 文件
基础配置里最容易漏掉的三个参数
只写 TimedRotatingFileHandler('app.log', when='D') 是不够的。缺了这几个,要么不归档、要么乱命名、要么占满磁盘。
-
backupCount=7:保留最近 7 天日志,超出的自动删除;不设或设为 0 就只留当前文件 -
encoding='utf-8':尤其处理中文日志时必加,否则 Windows 下可能报UnicodeEncodeError -
utc=False(默认值):使用本地时区判断“一天”;如需 UTC 时间滚动(例如部署在多时区服务器),显式设为True
如何避免凌晨重启导致日志重复或丢失?
如果服务每天凌晨 3 点重启,而 TimedRotatingFileHandler 在 2:59 触发滚动,3:00 重启后新进程会从头写 app.log,但旧的 app.log.2024-06-15 实际只包含不到 1 小时日志。这不是 bug,是设计使然。
- 解决思路:把滚动时机固定到整点,用
atTime参数。例如每天 00:00 滚动:atTime=datetime.time(0, 0) - 确保所有进程共用同一份日志配置,不要多个进程同时写同一个
TimedRotatingFileHandler实例(会冲突) - 若必须多进程写日志,改用
logging.handlers.RotatingFileHandler+ 外部定时脚本,或上logrotate(Linux)
一个最小可用的生产级配置示例
以下代码能稳定按天滚动、保留 7 天、支持中文、不因重启错乱:
立即学习“Python免费学习笔记(深入)”;
import logging
from logging.handlers import TimedRotatingFileHandler
import datetime
<p>logger = logging.getLogger('myapp')
logger.setLevel(logging.INFO)</p><p>handler = TimedRotatingFileHandler(
filename='app.log',
when='D',
interval=1,
backupCount=7,
encoding='utf-8',
delay=True,
atTime=datetime.time(0, 0) # 每天 00:00 滚动
)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)</p><p>logger.info('服务已启动')</p>注意 atTime 的时间是本地时区,且仅当 when='D' 或 'midnight' 时生效;delay=True 能防止程序启动时立即 open 文件,规避部分时区/权限问题。
真正麻烦的是跨多进程和容器环境——此时 TimedRotatingFileHandler 的文件锁和时间判断会失效,得换方案。


















