直接用crontab调度日志轮转本质是手动模拟logrotate逻辑,适用于无logrotate环境或需高度定制的轻量场景;关键在于轮转动作的安全性、可逆性、不丢日志、不卡进程;单文件宜控制在50–100mb以兼顾可读性与性能。

直接用 crontab 调度日志轮转,本质是“手动模拟 logrotate 的切割逻辑”,适用于无 logrotate 环境、或需高度定制轮转行为(如按特定关键词截断、保留带时间戳的原始文件名、配合业务状态判断是否轮转)的轻量场景。关键不在“调度”,而在“轮转动作本身是否安全、可逆、不丢日志、不卡进程”。宿主机内核对单文件读取效率并无硬性“最佳尺寸红线”,但实践表明:超过 100MB 的纯文本日志,tail -f 响应变慢、grep 查找延迟上升、vim/nano 打开易卡顿;2GB 以上则可能触发 ext4 文件系统大文件处理开销,影响 I/O 吞吐。因此,把单文件控制在 50–100MB 是兼顾可读性与性能的合理目标。
用 find + copytruncate 安全轮转(推荐)
这是最贴近 logrotate copytruncate 行为的方式,无需重启服务,不丢失任何一行日志:
- 原理:先复制当前日志为带时间戳的备份,再清空原文件(echo > /path/to/logfile 或 truncate -s 0 /path/to/logfile),应用进程因文件描述符未变,继续写入同一 inode,完全无感知
- crontab 示例(每小时检查一次,超 80MB 就轮转):
0 * * * * if [ $(stat -c "%s" /var/log/myapp.log 2>/dev/null | cut -d. -f1) -gt 83886080 ]; then cp /var/log/myapp.log /var/log/myapp.log.$(date +\%Y\%m\%d-\%H\%M) && truncate -s 0 /var/log/myapp.log; fi - 注意:stat -c "%s" 获取字节数,83886080 = 80MB;truncate -s 0 比 echo > 更原子、更安全,尤其对多进程写入场景
用 date + mv 配合服务重载(需支持 SIGHUP)
适用于 nginx、rsyslog、supervisord 等原生支持日志重载的服务,轮转更干净,但要求服务能响应信号重新打开日志文件:
- 步骤:重命名原日志 → 创建新空日志 → 发送 SIGHUP 让服务切换到新文件
0 2 * * * mv /var/log/nginx/access.log /var/log/nginx/access.log.$(date +\%Y\%m\%d) && touch /var/log/nginx/access.log && kill -HUP $(cat /var/run/nginx.pid) - 必须确认服务 PID 文件存在且权限可读,且该服务确实监听 HUP 信号(查文档或试运行 kill -HUP pid 是否无报错)
- 避免用 service nginx reload —— 它可能触发完整配置重载,带来额外开销
规避常见陷阱:三类“看似轮转实则埋雷”的操作
以下方式在 crontab 中高频出现,但极易导致磁盘不释放、日志丢失或服务中断:
- rm -f 日志文件:只要进程还在写,文件虽被删,空间仍被占用(lsof | grep deleted 可见),df 显示满但 du 不统计 —— 必须重启服务才能释放,不可用于生产
- mv 日志后不 touch 新文件:服务找不到目标路径,日志直接丢弃(静默失败),排查极困难
- 轮转脚本没加锁:若轮转耗时较长(如压缩大文件),下次 cron 触发时两个实例并发执行,可能相互覆盖或误删 —— 加 flock -n /tmp/rotate.lock -c 'your_rotate_cmd' 防重入
验证与兜底:让轮转真正可靠
仅靠 cron 时间点不等于任务成功。建议组合校验机制:
- 每次轮转后,用 ls -lh /var/log/myapp* 和 stat -c "%y %s" /var/log/myapp.log 记录到日志,确认大小归零、时间更新
- 加一条每日检查任务,报警超限文件:
0 6 * * * find /var/log -name "*.log" -size +100M -exec ls -lh {} \; >> /var/log/rotate-alert.log - 所有轮转命令末尾加 && echo "$(date): rotate OK" >> /var/log/rotate.log,便于快速定位失败时间点











