必须用copytruncate,因Java进程长期持有stdout日志文件句柄,rename轮转会致新日志写入旧文件而丢失;copytruncate先复制再清空原文件,保持inode不变,确保日志不丢失。

Java 应用若直接将日志输出到标准输出(如 catalina.out、nohup.out 或自定义的 stdout.log),且未在应用层配置 Logback/Log4j 的滚动策略,就极易产生单个超大日志文件。此时 logrotate 是最可靠、最轻量的兜底物理切分方案——关键在于正确处理“进程持续写入 + 文件被移动/清空”之间的冲突。
为什么必须用 copytruncate
Java 进程通常以追加模式(append=true)打开 stdout 重定向的目标文件,并长期持有该文件描述符。若 logrotate 默认使用 rename 方式轮转(即把原文件改名再新建),Java 进程仍会往已被重命名的旧文件中写入,导致新日志“消失”——看起来切分了,实际日志丢了。
copytruncate 是唯一安全选项:它先复制当前内容到归档文件,再立即清空原文件(truncate -s 0)。Java 进程因文件句柄未变,继续向同一 inode 写入,数据不丢失。
典型配置示例(以 catalina.out 为例)
在 /etc/logrotate.d/tomcat 中写入:
/opt/tomcat/logs/catalina.out {
daily
rotate 15
compress
delaycompress
missingok
notifempty
copytruncate
dateext
dateformat -%Y%m%d-%s
create 644 tomcat tomcat
}
说明:
- dateformat -%Y%m%d-%s 避免同天多次轮转时文件名冲突(加上秒级时间戳)
- create 644 tomcat tomcat 确保清空后新文件权限和属主正确,否则 Java 进程可能因权限不足写失败
- missingok 和 notifempty 防止服务未启动或日志为空时报错中断
验证与调试要点
配置后不要等 cron,立即验证:
立即学习“Java免费学习笔记(深入)”;
- 用
logrotate -d /etc/logrotate.d/tomcat查看模拟执行流程,确认是否匹配目标路径、是否启用 copytruncate - 手动触发一次:
logrotate -f /etc/logrotate.d/tomcat,然后检查:
– 原catalina.out是否变为空文件(ls -l 可见 size=0)
– 是否生成类似catalina.out-20260721-123456.gz的归档
– Java 进程是否仍在正常追加日志(tail -f catalina.out有实时输出) - 检查状态记录:
grep catalina /var/lib/logrotate.status,确认最后轮转时间已更新
常见失效原因排查
如果轮转没发生或日志丢失,优先检查这几项:
- crond 是否运行:
systemctl status cron;/etc/cron.daily/logrotate是否存在且可执行 -
/etc/logrotate.conf中include /etc/logrotate.d是否被注释(这是 70% 配置不生效的根源) - Java 进程是否以 root 启动但日志目录属主为普通用户?
create指令无法覆盖权限,需确保目录可写且属主匹配 - 磁盘空间是否已满?logrotate 在空间不足时会静默跳过(可用
df -h快速确认)


















