Linux logrotate 轮转后应用如何重新打开新日志文件
来源:17golang原创
时间:2026-09-13 11:01:37 344浏览 收藏
logrotate 轮转后,应用是否能写入新的 app.log,关键不在“文件名有没有回来”,而在进程持有的文件描述符是否已经从旧 inode 切换到新 inode。能响应 HUP 或提供 reload 接口的应用,应使用“重命名旧文件 + 创建新文件 + postrotate 通知”的方式;只有无法让应用关闭旧描述符时,才考虑 copytruncate。
create配合普通重命名轮转,会生成新的app.log;应用必须重新打开它。postrotate只负责执行通知脚本,不会替应用自动重开日志,HUP 或 reload 语义由应用决定。- 用
stat看 inode,再用lsof看进程 fd,才能确认应用没有继续写旧文件。
直接用logrotate自带的copytruncate配置模式,或者给对应应用发USR1信号通知它重载日志句柄,是绝大多数场景下最稳妥的实现方式,不用重启业务进程也不会丢失正在写入的日志内容。
官方地址:https://github.com/logrotate/logrotate/
先分清移动文件和原地截断
普通轮转通常把原来的 app.log 改名为 app.log.1,然后按 create 规则建立一个同名新文件。此时目录里虽然重新出现了 app.log,但它已经是另一个 inode。应用如果一直持有旧文件描述符,日志仍会写进已经改名的 app.log.1。
copytruncate 是另一条路:它复制内容后在原位置截断文件,应用不需要重开描述符,但官方手册明确提示复制与截断之间存在很小的数据丢失窗口。它适合无法被通知关闭日志的程序,不是“配置了就更安全”的默认答案。
| 方式 | 应用是否要 reopen | 主要代价 |
|---|---|---|
| rename + create | 需要 | 依赖 HUP、reload 或重启语义 |
| copytruncate | 不需要 | 复制窗口可能丢少量日志 |
用 postrotate 让应用重新打开日志
把规则放在 /etc/logrotate.d/myapp,让轮转动作和通知动作处于同一个规则中。下面示例假定应用的 PID 文件是 /run/myapp.pid,并且约定收到 HUP 后重新打开日志;如果应用文档规定使用其他信号或自定义 reload 命令,应替换这一行。
/var/log/myapp/app.log {
daily
rotate 7
missingok
notifempty
create 0640 myapp adm
sharedscripts
postrotate
# 轮转完成后通知应用重新打开新的 app.log
if [ -s /run/myapp.pid ]; then
kill -HUP "$(cat /run/myapp.pid)"
fi
endscript
}
这里的顺序很重要:postrotate 在轮转后、压缩前执行,通知脚本失败时也可能影响后续处理。sharedscripts 适合一个规则匹配多个文件且只需通知一次的场景;单文件规则可以省略它。不要把 HUP 当成 Linux 对所有程序的统一“重开日志”接口,它只是发送信号,应用是否实现该语义要看自身文档。

轮转后怎么确认已经写入新文件
先用调试模式查看规则是否匹配,再在维护窗口强制轮转。示例命令只用于读者在自己的主机上操作,输出中的 PID、inode 和路径应以现场值为准。
# 只展开规则,不真正修改文件
sudo logrotate -d /etc/logrotate.d/myapp
# 确认规则无误后,在维护窗口强制轮转一次
sudo logrotate -f /etc/logrotate.d/myapp
# 对照新旧日志的 inode;两个数字不同才说明生成了新文件
stat -c 'path=%n inode=%i size=%s' /var/log/myapp/app.log /var/log/myapp/app.log.1
# 查看应用当前打开的日志描述符,确认 fd 指向新 app.log
sudo lsof -p "$(cat /run/myapp.pid)" | grep '/var/log/myapp/app.log'
判断时不要只看文件大小:如果 app.log 与 app.log.1 的 inode 不同,并且 lsof 显示应用 fd 指向当前 app.log,才说明 reopen 已完成。若旧文件仍带有 (deleted) 或 fd 指向 app.log.1,通常是应用没有处理信号、PID 不对,或 reload 发生在规则执行失败之后。

哪些情况不该直接发送 HUP
如果应用没有记录 HUP 的行为,盲目发送可能导致配置重载、连接变化,甚至进程退出。先查应用的日志文档或 service 单元,确认它提供的是 HUP、USR1、systemctl reload myapp,还是只能平滑重启。由 systemd 管理的服务,也可以把通知动作改成明确的 reload 命令,但要确保命令成功返回。
另一个常见边界是权限:logrotate 可能以 root 执行,而应用以 myapp 用户运行。create 的 owner、group 和 mode 要让应用可写,通知脚本还要读取正确的 PID 文件。压缩建议放在应用确认 reopen 之后;对无法 reopen 的程序才考虑 copytruncate,并接受它的短暂数据风险。
常见问题
为什么新 app.log 有内容,应用却还在写 app.log.1?
文件名变化不等于文件描述符变化。检查 HUP/reload 是否被应用支持,再用 lsof 对照 fd 实际指向的 inode。
postrotate 里应该写 kill 还是 systemctl reload?
以应用官方约定为准。PID 稳定且 HUP 明确表示 reopen 时可以用 kill;由 systemd 管理并提供 reload 动作时,systemctl reload 通常更能表达服务边界。
什么时候使用 copytruncate?
只有在应用无法被可靠通知关闭并重新打开日志时考虑。它能保持原 inode,但要评估复制到截断之间的日志丢失窗口和高并发写入影响。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
文章 · linux | 2小时前 | Linux · systemd · 服务器运维 · 日志排查 · journalctl · journalctl启动筛选 journalctl查看上一次启动 journalctl -b -1 systemd日志按启动过滤 Linux启动日志排查222 收藏
-
402 收藏
-
197 收藏
-
345 收藏
-
420 收藏
-
186 收藏
-
245 收藏
-
456 收藏
-
435 收藏
-
492 收藏
-
414 收藏
-
204 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习