旧日志文件为空,通常因usr1信号未生效或缓冲未刷新:nginx未切换写入文件,或buffer/flush设置导致延迟落盘;需通过inode变化和lsof验证信号是否成功。

旧日志文件没数据,大概率不是切割失败,而是 Nginx 还在往新文件写,而你误把“刚 rename 的旧文件”当成了“应该有昨天数据的文件”——本质是没等 USR1 信号生效就去查,或压根没发成功。
为什么 postrotate 发了 kill -USR1,但旧文件还是空的?
logrotate 执行顺序是:rename 日志 → 运行 postrotate 脚本 → 退出。如果 kill -USR1 没执行成功,Nginx 就不会新建 access.log,而是继续往 rename 后的旧文件(比如 access.log.1)里写——但你可能正盯着刚 rename 出来的 access.log.1 看,发现它一开始是空的,就以为“没写进去”。其实它要等几秒甚至几十秒才开始有内容,因为:
- Nginx worker 进程不是立刻 flush 缓冲区,尤其用了
buffer=64k flush=3s时,最多会攒 3 秒数据再落盘 - 如果当天流量极低(比如凌晨),
access.log.1可能几小时都只有零星几行 -
kill -USR1失败后,Nginx 根本没切换文件,所有新日志仍写进当前access.log,而access.log.1自然一直空着
怎么确认 kill -USR1 到底有没有生效?
别只看日志文件名,直接查 inode 和进程打开的文件描述符:
运行 ls -i /var/log/nginx/access.log*,观察轮转前后 inode 是否变化;再执行 lsof -p $(cat /var/run/nginx.pid) | grep access.log,看输出里是不是还挂着旧的 inode 号。如果 inode 没变、lsof 显示的仍是 access.log(不是 access.log.1),说明 kill -USR1 没起作用。
常见失效原因:
-
/var/run/nginx.pid文件不存在或路径错(比如实际在/run/nginx.pid或/usr/local/nginx/logs/nginx.pid) - logrotate 脚本没权限读取 pid 文件(尤其 Nginx 以
www-data运行,而 logrotate 用 root 运行但没加su www-data www-data) - postrotate 块里漏了
if [ -f ... ]判断,pid 文件一缺失就报错退出,后续命令不执行
配置里 missingok + notifempty 组合容易导致“静默丢日志”
这两个选项看着很安全,但合起来会埋坑:missingok 让 logrotate 忽略日志文件不存在的错误,notifempty 让它跳过空文件——结果就是:某天没流量,access.log 是空的,logrotate 直接跳过本次轮转,不 rename、不发 USR1、也不创建新文件。第二天所有访问日志全挤进一个没被轮转过的 access.log,而你以为“昨天的日志该在 .1 里”,其实压根没生成。
更稳妥的做法:
- 去掉
notifempty,强制每天轮转(哪怕空文件也 rename + USR1) - 确保
create 0644 nginx nginx存在,这样即使某天没日志,新access.log也能被重建 - 加
dateext和dateformat -%Y%m%d,让归档文件名自带日期,避免靠编号(.1、.2)猜错时间
高并发下 buffer 设置会让“旧文件看起来空”持续更久
如果你在 nginx.conf 里配了 access_log /var/log/nginx/access.log main buffer=64k flush=5s,那 Nginx 会把最多 64KB 或 5 秒内的日志先缓在内存里。轮转触发后,这部分缓冲区内容不会立刻刷进 access.log.1,而是等下次 flush 或进程 reload 才落盘。所以你查 access.log.1 时看到空,可能是缓冲还没倒出来。
验证方法:
- 临时改小 flush 时间:比如
flush=1s,再手动跑一次logrotate -f /etc/logrotate.d/nginx,观察access.log.1是否 1~2 秒内就有内容 - 用
strace -p $(cat /var/run/nginx.pid) -e write看 worker 进程是否真在往新文件 fd 写(需 root 权限) - 检查
error.log里有没有 “open() “/var/log/nginx/access.log” failed (13: Permission denied)” 类报错——权限不对时缓冲写入会静默失败,日志就真丢了
真正难排查的,是那种“旧文件有数据但比预期少”的情况:它既不是完全空,又不像全量,往往卡在缓冲未清、USR1 部分生效、或采集端(如 Filebeat)在 rename 瞬间漏掉最后几百字节——这时候得对照原始文件 inode、采集器 registry、以及服务端时间戳三者交叉验证,不能只盯一个文件看。











