rotate 参数决定保留几个归档文件,如 rotate 7 表示最多保留 access.log.1 至 .log.7 共 7 个归档,超出的最老文件被自动删除;它不感知时间,仅按文件数量控制清理。

logrotate 的 rotate 参数决定保留几个归档文件
FrankenPHP 自身不管理日志轮转,必须依赖系统 logrotate。真正控制“保留多少个旧日志”的,是配置里的 rotate 值——它指定最多保留多少个归档(如 access.log.1、access.log.2…),超出的最老文件会被自动删除。
常见误区是以为 Caddy 的 roll 或 PHP 的 Monolog 能管这个,其实完全无效:Caddy 的 roll 不清理旧文件;Monolog 只处理应用层日志,对 FrankenPHP 的访问日志和错误日志毫无影响。
-
rotate 7:保留最近 7 天(或 7 个归档),适合磁盘小或流量稳定的环境 -
rotate 30:默认值,适合排查周期长、需回溯较久日志的场景 - 注意:
rotate计数包含所有.log.N文件,不含当前正在写的access.log
/etc/logrotate.d/frankenphp 配置必须带 copytruncate
没加 copytruncate,rotate 再大也没用——因为轮转时 Caddy 进程还在往原文件写,logrotate rename 会失败,导致后续轮转卡住、日志停止更新,甚至出现 access.log.1 为空的现象。
copytruncate 的作用是:先复制内容到归档,再清空原文件(truncating),保证 Caddy 持续写入同一 inode,不中断也不丢日志。
立即学习“PHP免费学习笔记(深入)”;
- 必须和
create 644 www-data www-data配合使用,否则新日志文件权限错误,Caddy 写不进去 - 路径要严格匹配 Caddyfile 中
log指令的output路径,例如/var/log/frankenphp/*.log - 手动验证命令:
sudo logrotate -f /etc/logrotate.d/frankenphp,然后检查ls -l /var/log/frankenphp/是否有.log.1且原文件变空
按大小触发轮转比 daily 更可靠
用 daily 触发,可能某天流量突增,单个 access.log 涨到几 GB 才轮转;而 size 50M 能更及时切分,避免单文件过大引发 I/O 拥塞或 inode 耗尽。
但要注意:logrotate 的 size 是按文件大小判断,不是按写入量实时监控,所以需留一点缓冲空间——比如设 size 50M,实际文件可能略超 50MB 才触发,不影响 rotate 的计数逻辑。
- 替换
daily为size 50M即可,其他参数(rotate、copytruncate)保持不变 - 不要混用
daily和size,logrotate 只认第一个匹配的触发条件 - 容器环境建议优先用
size,因系统时间可能漂移(尤其在频繁重启的 dev 环境)
PHP 应用日志和 Caddy 日志要分开管
很多人想用同一个 rotate 值统一控制所有日志,但 FrankenPHP 的两类日志来源不同、生命周期不同,硬绑在一起反而容易出问题:
- Caddy 日志(
access.log、error.log):由/etc/logrotate.d/frankenphp管,靠copytruncate安全轮转 - PHP 应用日志(如 TP6 的
runtime/log/):走 MonologRotatingFileHandler,靠$maxFiles控制份数,且必须关 buffer(false)、显式传DateTimeZone - 二者路径、权限、触发时机都不同,强行共用一套配置会导致轮转错位、权限丢失或当日文件被误删
最关键的细节是:logrotate 的 copytruncate 对 PHP 应用日志无效,因为那些文件是 PHP 进程自己打开写的;而 Monolog 的轮转又不能替代 Caddy 层日志管理——它们根本不在一个层面。



















