logrotate 必须设置 rotate 和 maxage 才能清理日志;php-fpm 日志路径需与配置完全一致;monolog 轮转由 $maxfiles 控制,与 logrotate 无关。

logrotate 配置里必须设置 rotate 和 maxage
PHP 本身不处理日志轮转,实际是系统级工具(如 logrotate)在管理。只配了 daily 或 size 不等于旧日志会自动消失——必须显式告诉它“最多留几个”或“过期几天就删”。rotate 7 表示保留最近 7 个归档文件(如 access.log.1 到 access.log.7),而 maxage 30 是按文件修改时间删超过 30 天的归档(哪怕还没轮到第 7 个)。两者可共存,maxage 优先级更高。
-
rotate 5+maxage 14:某天发现error.log.6存在且修改时间是 15 天前 → 立即被删 - 没写
rotate?即使有maxage,logrotate 也不会做任何归档动作,更不会清理 - PHP-FPM 的
access.log和error.log路径要和 logrotate 配置里的path完全一致,否则匹配不到
PHP-FPM 日志路径写错导致轮转失效
常见错误是把 access.log 写成 /var/log/php-fpm/access.log,但实际 PHP-FPM 配置里是 access.log = /var/log/php-fpm/www-access.log。logrotate 不会模糊匹配,路径差一个字符就不触发。用 ps aux | grep php-fpm 或查 php-fpm.conf 里的 access.log 和 error_log 实际值,再同步到 logrotate 配置中。
- 检查真实路径:
grep -E "^(access\.log|error_log)" /etc/php-fpm.d/www.conf - logrotate 配置中路径必须完整、无通配符,例如:
/var/log/php-fpm/www-access.log - 如果用了
include /etc/logrotate.d/php-fpm,确保该文件存在且权限为 644,root 可读
logrotate 手动测试与强制执行
改完配置别等明天 cron,先用 --debug 看是否识别到文件、是否计划删除,再用 --force 强制跑一次验证行为。尤其注意 missingok 和 notifempty 的影响:前者让 logrotate 忽略“文件不存在”的报错,后者防止空日志被轮转(也就不会产生新归档,自然谈不上清理)。
- 调试命令:
logrotate --debug /etc/logrotate.d/php-fpm(不改文件,只打印动作) - 强制执行:
logrotate --force /etc/logrotate.d/php-fpm - 如果看到
error: error.log:1234567890: No such file or directory,说明路径不对或文件还没生成过
PHP 应用层日志(如 Monolog)需独立配置清理
如果 PHP 代码里用 Monolog\Handler\RotatingFileHandler,那轮转逻辑完全在 PHP 进程内,和系统 logrotate 无关。它的清理靠构造时传入的 $maxFiles 参数控制,比如 new RotatingFileHandler('/var/log/app.log', 30) 表示最多保留 30 个日志文件。注意这个数字是“文件总数”,不是“天数”;且每次写日志时才会检查并删除最老的归档,不是定时任务。
立即学习“PHP免费学习笔记(深入)”;
- Monolog 的
$maxFiles值设太小(如 3)会导致日志很快被覆盖,排查问题时找不到历史记录 - 和系统 logrotate 混用同一目录?可能互相干扰——比如 logrotate 把
app.log.5删了,Monolog 下次轮转时却试图重命名app.log.4→app.log.5,结果失败 - 建议:PHP 应用日志走 Monolog 自带轮转,系统服务日志(PHP-FPM、Nginx)走 logrotate,物理路径分开
rotate 和 maxage 是硬开关,不设就等于没清理;PHP-FPM 路径错一个字符,整个配置就静默失效;Monolog 的 $maxFiles 是运行时逻辑,和系统级轮转互不感知——这三处最容易漏掉或配错。











