postrotate脚本不执行的首要原因是logrotate未真正触发轮转,常见于日志大小未达标、时间未到或配置缺失create/rotate等必要指令;需用logrotate -d调试确认是否出现“running postrotate script”,若无则先解决轮转条件问题。

Postrotate 脚本不执行?检查 logrotate 是否真触发了它
logrotate 默认在轮转完成、新日志文件已创建后才运行 postrotate 段,但很多人误以为只要配置写了就一定执行。常见原因是:logrotate 实际没触发轮转(比如日志大小未达标、时间未到),或配置中漏了 create 或 rotate 等必要指令导致整个轮转流程跳过 postrotate。
验证方法:手动强制触发并观察输出:
logrotate -d /etc/logrotate.d/myapp
注意:-d 是 debug 模式,会打印每一步是否执行,重点看是否有 running postrotate script 行。若无,说明轮转根本没发生——先解决轮转条件问题,再谈重载。
平滑重载失败?信号发给谁、怎么发很关键
“平滑重载”本质是向正在运行的主进程发送 SIGHUP(或其他服务约定的信号),让它重新打开日志文件句柄。但直接用 kill -HUP `cat /var/run/myapp.pid` 很容易出错:
-
/var/run/myapp.pid文件可能不存在、权限不对、或内容不是有效 PID - 服务可能没写 PID 文件(比如用 systemd 管理时默认不写)
- 多进程模型下,只 kill 主进程不够,子进程仍持有旧日志 fd
更稳妥的做法是委托服务自身管理重载逻辑:
postrotate
if [ -f /var/run/myapp.pid ]; then
kill -HUP $(cat /var/run/myapp.pid)
else
systemctl reload myapp.service 2>/dev/null || true
fi
endscript
优先走 PID 方式,失败则 fallback 到 systemctl reload;|| true 防止某条命令失败导致整个 postrotate 中断(logrotate 会把非零退出视为错误并报 warning)。
脚本里不能用 bash 特性?logrotate 调用的是 /bin/sh
logrotate 内部调用 postrotate 时,固定使用 /bin/sh 解释器,不是你终端里的 bash。所以以下写法会静默失败:
-
[[ -f ... ]](bash 扩展,sh 不支持)→ 改用[ -f ... ] -
source ~/.bashrc(sh 没有 source,只有.)→ 改用. /etc/myapp/env.sh -
$(systemctl is-active --quiet myapp)(--quiet 是 systemctl 的 bash-friendly 选项,但 sh 下没问题;真正风险是命令本身不可用)→ 确保systemctl在/bin/sh环境中 PATH 可达,或写绝对路径/usr/bin/systemctl
测试方式很简单:把脚本内容复制出来,用 sh -n your_script.sh 检查语法,再用 sh -x your_script.sh 模拟执行看行为。
为什么 reload 后旧日志还在写?文件句柄没释放
即使 postrotate 成功发送了 SIGHUP,某些程序(尤其是没正确处理信号的 C 程序或老版本 Nginx)不会主动 close+reopen 日志 fd,导致新日志继续追加到旧文件(已被 logrotate 重命名)。这不是 logrotate 的问题,而是服务端缺陷。
验证方法:轮转后立刻执行
lsof -nP -p $(cat /var/run/myapp.pid) | grep 'DEL\|deleted'
如果看到类似 /var/log/myapp.log (deleted),说明进程还在往已删除(即被 logrotate 移走)的文件写——必须升级服务或改用支持 copytruncate 的方案(但该模式有丢日志风险,慎用)。
真正可靠的解法是确认服务文档明确写了 “SIGHUP reloads log files”,否则不要假设它能平滑重载。











