RotatingFileHandler 日志不按大小切分是因为仅在写入新日志且当前文件超 maxBytes 时触发滚动,非定时检查;需确保有日志输出、maxBytes 不宜过小(建议≥1024)、多进程须用 QueueHandler。

RotatingFileHandler 为什么日志不按大小切分
常见现象是配置了 maxBytes 和 backupCount,但日志始终只写入一个文件,从不生成 app.log.1、app.log.2 等备份文件。根本原因是:RotatingFileHandler 只在「当前日志文件大小超过 maxBytes 且即将写入新日志时」才触发滚动,不是定时检查或后台轮询。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 确保每次写日志都调用
logger.info()等方法,空跑不写日志不会触发滚动 -
maxBytes值不宜过小(比如设成 10),因为 Python 的文件缓冲和编码(如 UTF-8 中文占 3 字节)会导致实际文件增长与预期有偏差;建议最小设为1024(1KB)起 - 如果程序长期静默(无日志输出),滚动永远不会发生——这不是 bug,是设计使然
- 注意:
RotatingFileHandler不支持同时被多个进程安全写入;多进程场景必须用QueueHandler+ 单独监听进程,否则备份文件可能损坏或丢失
TimedRotatingFileHandler 按天切分却总在凌晨 0 点卡住
设置 when='D' 后,期望每天 00:00 创建新文件,但发现日志仍往旧文件写,甚至第二天早上才发现切换延迟数小时。这是因为 TimedRotatingFileHandler 的滚动时机依赖「首次写日志的时间点」,而非系统时钟整点。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 它内部记录上一次滚动时间
self.rolloverAt,每次写日志前判断是否已超时;若程序凌晨前就启动并写过日志,那下次滚动就是「首写时间 + 1 天」,不是固定 00:00 - 改用
when='midnight'并显式指定atTime(Python 3.9+)可更可控,例如:atTime=datetime.time(0, 0) - 如果必须严格按日历日切分,推荐用
when='D'+ 每天首次写日志前手动检查:handler.doRollover()(需先判断是否已过 midnight) - 注意
backupCount对此 handler 有效,但删除旧文件的动作发生在每次 rollover 时,不是定时清理
多个 Handler 写同一个日志路径导致内容错乱
代码里不小心给同一个 logger 添加了两个 RotatingFileHandler,都指向 'app.log',结果打开文件看到日志行交错、重复、甚至半截中文乱码。这是因为两个独立的 file object 同时 seek/write,OS 层面无法保证原子性。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 绝对避免对同一路径创建多个
FileHandler子类实例(包括RotatingFileHandler、TimedRotatingFileHandler) - 若需不同策略(如一份保留 7 天,一份保留 30 天),应使用不同路径:
'app_daily.log'和'app_full.log',再各自配 handler - 共享日志路径的唯一安全方式是:单个 handler + 多个 filter(如按 level 或 module 过滤),而不是多个 handler
- 调试时可用
logger.handlers打印当前所有 handler,确认是否重复添加(常见于多次 import 或 reload 模块)
重启程序后旧日志文件没被自动压缩或清理
设置了 backupCount=5,但程序重启几次后发现 app.log.1 到 app.log.10 全在,超出限制。这是因为 RotatingFileHandler 的清理逻辑只在「本次 rollover 过程中」执行,不扫描磁盘做兜底清理。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 每次 rollover 时,它会重命名旧文件(
.1 → .2)、删除最老的(.5被删),但前提是这些文件名符合它的命名规则(即由它自己生成) - 手动创建的
app.log.99或上次异常退出残留的app.log.1.tmp不会被识别和清理 - 如需强保障,启动时加一段清理逻辑:
import glob, os<br>for f in sorted(glob.glob('app.log.*'), reverse=True)[5:]:<br> os.remove(f) - 注意:不要在 handler 初始化阶段做清理,可能干扰其内部状态;放到 logger 配置完成、首次写日志前更稳妥
滚动日志真正的复杂点不在参数配置,而在于「时间语义」和「进程边界」——前者决定切分时机是否符合业务预期,后者决定多实例部署时文件是否安全。这两处不厘清,光调参数只是隔靴搔痒。

















