logrotate 是最稳妥的日志按日期重命名与切割方案,原生支持 dateext、dateformat(如-%y%m%d-%s)等特性,避免时区、跨天、并发写入等问题,且不依赖进程状态或应用配合。

用 logrotate 按日期重命名并切割日志最稳妥
直接硬写 shell 脚本按日期重命名日志容易漏时区、跨天、并发写入等问题,logrotate 是 Linux 标准方案,原生支持日期格式化命名和自动轮转。logrotate 不依赖进程是否退出,也不要求应用配合,只要文件路径稳定就能工作。
关键配置项示例(放在 /etc/logrotate.d/myapp):
/var/log/myapp/app.log {
daily
missingok
rotate 30
compress
dateext
dateformat -%Y%m%d-%s
create 644 root root
sharedscripts
postrotate
systemctl reload myapp.service > /dev/null 2>&1 || true
endscript
}
-
dateext启用日期后缀(默认是-YYYYMMDD) -
dateformat可自定义,但注意:%s是秒级时间戳,能避免同秒多次轮转冲突;%Y%m%d更简洁但不防重名 - 不要用
copytruncate+dateformat组合——它不重命名原文件,只是清空,达不到“按日期重命名”的目的 - 如果日志由
systemd管理,优先用journald配合systemd-cat,比文件轮转更可靠
手动切割时用 mv + date 要避开纳秒/时区陷阱
临时调试或非标准场景下需手动操作,常见错误是直接写 mv app.log app.log-$(date +%F) ——这在跨天执行时可能覆盖前一天的归档,且没处理并发写入。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 务必加
2>/dev/null抑制date时区警告,否则 cron 里可能静默失败 - 用
$(date -u +%Y%m%dT%H%M%SZ)强制 UTC 时间,避免本地时区导致命名错乱 - 先
cp再truncate -s 0或>清空原文件,比mv更安全(尤其当程序用inotify监控文件名时) - 示例安全命令:
cp /var/log/app.log /var/log/app.log-$(date -u +%Y%m%dT%H%M%SZ) && truncate -s 0 /var/log/app.log
logrotate 的 dateformat 不支持毫秒和中文,别白费劲
有人想用 %3N(毫秒)或 %Y年%m月 命名,但 logrotate 底层调用的是 strftime(3),只支持 C 标准库支持的格式符,%3N 是 glibc 扩展且 logrotate 未启用,中文格式则根本不可用。
- 可用的日期符:仅
%Y %m %d %H %M %S %s等基础项(%s是 Unix 时间戳,最实用) - 如果真需要毫秒级区分,改用
dateformat -%Y%m%d-%H%M%S-+ 随机后缀,或切到rsyslog的$year $month ...模板 - 检查生效方式:
logrotate -d /etc/logrotate.d/myapp(dry-run),别等真出问题才看
应用自己写日志时,strftime 格式和系统 LC_TIME 有关
如果用 Python/Go/Java 等语言自己控制日志文件名(比如 logging.handlers.TimedRotatingFileHandler),生成的日期字符串实际受系统 locale 影响,不是代码里写的格式就一定生效。
- Python 中
TimedRotatingFileHandler的when='midnight'依赖time.localtime(),若容器内没设ENV TZ=UTC,可能在凌晨 5 点轮转 - Go 的
log/slog或第三方库如lumberjack默认用本地时间,需显式传time.UTC - 最稳做法:所有服务统一设
export TZ=UTC,并在日志配置里显式指定time.Now().UTC().Format(...)










