直接rm或truncate日志文件会导致日志丢失或磁盘空间不释放,因php进程仍持有原文件句柄;推荐mv重命名后发送usr1信号让php-fpm重新打开日志文件。

不需要关闭 PHP 服务,log 文件可在线清理,关键在于避免进程写入时被截断或丢失日志。
为什么直接 rm 或 truncate 可能出问题
PHP(尤其是通过 fpm 或 apache 模块运行时)通常将错误日志、访问日志等以追加模式(FILE_APPEND)持续写入文件。若用 rm logfile 删除,文件 inode 被释放,但正在写入的进程仍持有旧文件句柄,日志会继续写入“已删除但未关闭”的文件(磁盘空间不释放);若用 truncate -s 0 logfile,则可能在写入中途清空,导致部分日志行被截断或丢失。
推荐做法:重命名 + 通知进程重新打开日志文件
这是最稳妥的在线清理方式,适用于 php-fpm、nginx、apache 等常见组合:
-
mv /var/log/php-fpm/www-error.log /var/log/php-fpm/www-error.log.20240520—— 原子重命名,不影响当前写入 - 触发日志 reopen:
kill -USR1 $(cat /var/run/php-fpm.pid)(php-fpm支持该信号,会自动创建新www-error.log并继续写入) - 旧日志文件可后续压缩或删除:
gzip /var/log/php-fpm/www-error.log.20240520
注意:USR1 信号行为依赖 php-fpm 配置中 error_log 是否为绝对路径且可写;若使用 systemd,也可用 systemctl kill --signal=USR1 php-fpm。
立即学习“PHP免费学习笔记(深入)”;
如果不用信号,改用 copytruncate(logrotate 场景)
当用 logrotate 管理 PHP 日志时,务必启用 copytruncate 选项:
"/var/log/php-fpm/www-error.log" {
daily
missingok
rotate 30
compress
copytruncate
}
copytruncate 的原理是:先拷贝日志内容,再清空原文件(而非删除),这样进程无需重启或 reload 就能继续写入同一路径。它比 create 更安全,但存在极小概率丢失最后几行(因拷贝与清空之间有微小窗口)。
PHP 应用层日志(如 monolog、file handler)怎么处理
若 PHP 代码自己用 file_put_contents($log, ..., FILE_APPEND) 写日志,无法靠外部信号 reopen,需自行支持日志轮转逻辑:
- 检查文件大小,超限后
rename($log, $log . '.20240520'),再继续写原路径 - 或使用
Monolog\Handler\RotatingFileHandler,它内部用fopen(..., 'a')+ 定期 rename,天然支持在线轮转 - 避免在脚本中用
file_put_contents($log, '', LOCK_EX)清空——这会阻塞其他写入请求
真正麻烦的不是“能不能清”,而是“清完谁还在写、往哪写、有没有丢”。只要日志文件路径没变、进程没被强制 kill,绝大多数 PHP 日志场景都能做到完全不停服。唯一要盯紧的是:确认你的日志写入方是否响应 USR1,或者是否用了不兼容的清空方式。











