PHP-FPM慢日志不支持内置切割,因主进程持续写入单文件句柄且无重开机制;必须用logrotate配合copytruncate管理,否则会导致日志丢失或写入错乱。

PHP-FPM慢日志(slowlog)本身不支持内置切割,必须交由 logrotate 统一管理;硬要在 PHP 配置里做轮转或用脚本 rename,大概率导致日志丢失或写入错乱。
为什么不能在 php-fpm.conf 里自己切 slowlog
slowlog 是 PHP-FPM 主进程直接 fopen 并持续 fwrite 的单文件句柄,没有 fclose/reopen 机制。你改名、清空、mv 它,FPM 进程仍往原 inode 写——新文件永远为空,旧文件越滚越大。
- 常见错误现象:
tail -f /var/log/php-fpm/slow.log看不到新内容,但磁盘空间还在涨;lsof -p $(cat /var/run/php-fpm.pid) | grep slow显示它仍持有着已“删除”文件的句柄 - PHP-FPM 不提供
slowlog_max_size或slowlog_rotate这类参数,官方明确不支持运行时轮转 - 试图用 cron +
mv+kill -USR1会失败:USR1 是 Apache 风格信号,PHP-FPM 只认USR2重开日志,且仅对error_log有效,对slowlog无效
logrotate 配置 slowlog 的关键三步
把 slowlog 当作普通日志交给系统工具处理,核心是 copytruncate + 正确权限 + 无重启依赖。
- 确认 slowlog 路径已在 php-fpm pool 配置中固定,例如
slowlog = /var/log/php-fpm/slow.log(不能带日期变量) - 在
/etc/logrotate.d/php-fpm中添加段落(路径需与 slowlog 一致):/var/log/php-fpm/slow.log { daily missingok rotate 30 compress delaycompress notifempty create 640 www-data www-data sharedscripts copytruncate postrotate if [ -f /var/run/php-fpm/php-fpm.pid ]; then kill -USR2 $(cat /var/run/php-fpm/php-fpm.pid) 2>/dev/null || true fi endscript } -
copytruncate是必须项:logrotate 先复制内容再清空原文件,FPM 进程无感知继续写;没有它,mv后日志就丢了 -
create 640 www-data www-data确保新空文件权限正确,否则 PHP-FPM worker 因无写权限卡住
验证是否生效 & 容易被忽略的坑
配置不是写完就完事,几个真实场景下容易翻车的点:
立即学习“PHP免费学习笔记(深入)”;
- 测试命令必须带
-f强制执行:logrotate -f /etc/logrotate.d/php-fpm,然后立刻检查:ls -la /var/log/php-fpm/slow.log*是否生成slow.log.1且原文件大小归零 - 如果
slow.log所在目录属主不是www-data(比如是root),即使create设了权限,logrotate 也可能因无目录写权限失败——用logrotate -d /etc/logrotate.d/php-fpm查调试输出 - 多个 PHP-FPM 版本共存时(如 8.1 和 8.2),务必确认
slowlog路径和php-fpm.pid路径对应正确版本,别混用/var/run/php8.1-fpm.pid去发 USR2 给 8.2 进程 - 高并发下,
copytruncate虽安全,但仍有极小窗口(毫秒级)可能丢最后几行;若业务对慢请求审计要求极高,应改用syslog+rsyslog的流式转发,绕过文件落地



















