Linux日志切割通过USR1信号实现平滑切换:服务监听USR1后重开日志文件,logrotate在postrotate中发送该信号,确保零停机、无丢日志。

Linux 中日志切割本身不直接响应信号,但信号是实现“服务不中断前提下完成日志切换”的关键桥梁。核心思路是:服务进程监听特定信号(如 USR1),收到后主动关闭当前日志文件句柄、重新打开新文件;而 logrotate 或脚本在切割前发送该信号,确保写入不丢、切换平滑。
USR1 是最常用的日志重载信号
多数主流服务(Nginx、Apache、rsyslog、自研 Go/Python 服务)默认将 USR1 定义为“重新打开日志文件”信号。它不重启进程,只刷新 I/O 句柄,因此零停机。例如:
- Nginx 收到
kill -USR1 $(cat /var/run/nginx.pid)后,会立即用新文件名(如access.log)继续写入,旧文件可安全归档 - rsyslog 使用
systemctl kill --signal=USR1 rsyslog触发日志重载 - 自定义服务需在代码中注册 signal handler,捕获 USR1 后执行
fclose(old_fd); fopen(log_path, "a")
logrotate 配合 postrotate 发送信号
logrotate 自身不发信号,但支持 postrotate/endscript 块,在日志重命名完成后执行任意命令。这是标准做法:
- 配置示例(
/etc/logrotate.d/myapp):
/var/log/myapp/app.log {
daily
missingok
rotate 30
compress
copytruncate
postrotate
# 切割完成后通知服务重开日志
kill -USR1 $(cat /var/run/myapp.pid 2>/dev/null) 2>/dev/null || true
endscript
}注意:copytruncate 和 postrotate + USR1 二选一即可。前者适合无法修改代码的服务(靠复制清空原文件),后者更干净、无竞态风险。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
API 或监控触发时手动发信号
当需要按业务事件(如调用 /v1/log-rotate 接口)或流量突增时切割,可跳过 logrotate 的定时逻辑,直接组合操作:
- 先重命名日志:
mv /var/log/myapp/app.log /var/log/myapp/app.log.$(date +%s) - 再发信号让服务创建新日志:
kill -USR1 $(pidof myapp) - 最后压缩旧文件、清理(可选):
gzip /var/log/myapp/app.log.*
该流程无需 root 权限(只要对日志目录有写权限、对进程有 signal 权限),适合嵌入 API 处理逻辑中。
验证信号是否生效的简单方法
不要只看进程是否存活,要确认日志写入行为已切换:
- 执行信号命令前后,运行
lsof -p $(pidof myapp) | grep log,观察文件描述符指向的日志文件名是否更新 - 向服务发一条测试请求,检查新生成的日志文件是否有新增内容,原文件是否不再增长
- 若服务未响应 USR1,请查阅其文档确认支持的信号(少数用 HUP、SIGUSR2 或自定义)

















