swoole自身不支持日志自动切分,log_file仅写入固定文件;真正切分需依赖rotatelogs接管stderr、onworkerstart中自定义流过滤器,或独立日志路径+写入前校验。

为什么 swoole_set_process_name 和日志切分无关
很多人在查 Swoole 日志切分时,会误以为改进程名或用 error_log 配置就能触发自动轮转——其实 Swoole 自身不提供日志文件按大小/时间自动切分的能力。它的 log_file 配置项(如 'log_file' => '/tmp/swoole.log')只负责把日志写进一个固定文件,不会创建 .1、.2.gz 这类归档,也不检查文件大小或日期。
真正起作用的是外部工具或自定义逻辑,Swoole 本身只暴露了两个关键支持点:onWorkerStart 中可重定向 stdout/stderr,以及通过 swoole_async_writefile 或 file_put_contents(..., FILE_APPEND) 手动写日志——这两条路决定了你能不能插入手动切分逻辑。
用 rotatelogs 配合 error_log 实现零代码切分
如果你用的是 Apache 风格的 rotatelogs(常见于 Linux/macOS),它可以直接接管 Swoole 的标准错误流,无需修改 PHP 代码。前提是 Swoole 进程以守护模式启动,且未重定向 stderr。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 启动命令示例:
rotatelogs -l /tmp/swoole.log.%Y%m%d 86400 &1
-
-l表示使用本地时间而非 UTC;86400是秒数(即每天切一次);%Y%m%d是日期格式 - 注意:必须确保 Swoole 没调用
cli_set_process_title或其他导致stderr被覆盖的操作,否则日志会丢失 - 该方式对
swoole_http_server和swoole_websocket_server均有效,但无法区分 worker/task 进程日志来源
在 onWorkerStart 中用 stream_filter_append 动态切分
若需按大小切分、带进程 ID 标识、或兼容 Windows 环境,就得自己控制写入逻辑。核心思路是:在每个 worker 启动时,把 error_log 的输出目标替换成一个带切分判断的包装流。
- 先用
fopen('php://stderr', 'w')获取原始 stderr 句柄 - 用
stream_filter_append($fp, 'rotating_log', STREAM_FILTER_WRITE, [...])注入自定义 filter(需提前注册stream_filter_register) - filter 内部检查当前文件大小,超限则关闭旧文件、打开新文件(如
/tmp/swoole.worker_123.202405201422.log) - 注意:不能在 filter 中调用
error_log(),否则递归触发;所有日志必须走fwrite($fp, ...) - 推荐用
file_put_contents($path, $msg, FILE_APPEND | LOCK_EX)替代流操作,更可控且避免锁竞争
log_file + 定时脚本切分的边界情况
最轻量的做法是仍用 Swoole 原生 log_file,再配一个外部脚本定时 mv + touch。但要注意三个硬伤:
- Swoole 不会自动 reopen 日志文件,
mv后新日志仍写入原 inode,导致“文件名变了但内容还在旧文件里”——必须配合kill -USR2(如果启用了 reload 支持)或重启进程 - worker 进程可能正在写入,直接
mv会导致部分日志丢失或截断,需先kill -STOP再操作,代价高 - 多个 worker 共用同一
log_file时,切分脚本无法区分谁写了哪行,日志混杂,排查困难 - 因此,仅当单 worker、低频写入、且能接受分钟级延迟切分时才考虑此方案
真正稳定的切分,始终要落在「每个进程独立日志路径 + 写入前校验大小/时间」这个组合上,而不是依赖外部移动文件。Swoole 给你的自由度够用,但得自己把关时机和原子性。










