logrotate 的 size 参数必须显式启用且不能与 daily 等时间参数共存,单位须用小写(如 100m);切割需配合高频 cron 并启用 copytruncate 保证 Tomcat 持续写入原文件;小 size 易引发碎片风暴,建议起始值 50m;终极方案是用 Log4j2 接管 stdout。

logrotate 的 size 参数必须显式启用
Tomcat 的 catalina.out 是 stdout/stderr 重定向文件,它不会自动按大小切分,必须靠外部工具干预。logrotate 支持按大小切割,但前提是配置中**不能同时存在 daily(或 weekly)和 size** —— 二者互斥,logrotate 只会响应第一个匹配条件。
常见错误是写了 daily 又加 size 100M,结果日志每天切一次,完全忽略大小阈值。
- 正确写法:只保留
size 100M,去掉daily -
size单位支持100(字节)、100k、100m,注意大小写敏感,100M无效,必须用小写m - logrotate 每次运行时检查当前文件大小,仅当 ≥ 阈值才触发切割,因此需配合 cron 高频执行(如每小时一次),否则可能延迟很久才切
copytruncate 是 stdout 日志切割的生死线
Tomcat 进程始终持有 catalina.out 的文件描述符。若不截断原文件,即使 logrotate 把它重命名了,进程仍往旧 inode 写,导致原文件持续膨胀、磁盘空间不释放。
copytruncate 是唯一安全方案:先复制内容到新文件(如 catalina.out.1),再清空原文件(truncate),保证 Tomcat 继续写入的是同一个路径、同一个 inode。
- 缺省不开启,必须手动写入配置
- Windows 下的 logrotate(如 cygwin 或第三方移植版)也支持
copytruncate,但需确认版本 ≥ 3.8.0 - 不要用
create+nocopy组合——那会新建文件并让 Tomcat 切换到新 inode,但旧文件残留且仍在增长(因进程未重启)
避免 size 切割引发的小文件风暴
如果应用频繁打日志(比如每秒几百行),而 size 设得太小(如 size 1m),logrotate 可能在一小时内切出几十个碎片文件,造成 inode 耗尽或遍历缓慢。
这不是 logrotate 的 bug,而是配置失当:
- 生产环境建议
size 50m起步,再根据日志速率调整;可用du -sh /path/to/catalina.out观察 1 小时内增长量 - 不要把
rotate数设太高(如rotate 90),否则小文件积压严重;搭配compress和delaycompress减少磁盘压力 - 若需兼顾“按大小”和“按天”,只能二选一,或改用 Log4j2 接管 stdout(见下一条)
替代方案:用 Log4j2 完全接管 stdout(绕过 catalina.out)
logrotate 按量切 catalina.out 始终是补救手段。更彻底的做法是让 Tomcat 不再生成该文件,而是由 Log4j2 直接接管 stdout 输出,并原生支持 SizeBasedTriggeringPolicy。
关键步骤:
- 在
$CATALINA_HOME/conf/context.xml中设置swallowOutput="true" - 删掉或重命名
$CATALINA_HOME/conf/logging.properties(禁用 JUL) - 把
log4j2.xml放进$CATALINA_HOME/lib/,其中定义RollingFileappender 并启用SizeBasedTriggeringPolicy和DefaultRolloverStrategy - 确保
tomcat-juli-adapters.jar和log4j2相关 jar 已就位(Tomcat 8.5+ 原生兼容)
这样 catalina.out 就会变为空或消失,所有日志走 Log4j2 管控,按大小滚动、压缩、删除全部可控,无需依赖系统级工具。
真正难的不是配置,而是确认 swallowOutput="true" 是否生效——如果 catalina.out 仍有新增内容,说明接管失败,得回头查 classpath 或 JUL 冲突。

















