CLI (命令行) 模式通常用于运行定时任务 (Cron)、处理队列 (Queue Workers) 或执行守护进程。本指南涵盖了从基础的实时写入配置到高级的 Supervisor 托管架构的完整日志策略。
无论是否使用进程管理工具,CLI 环境下有两个核心参数必须调整,以防止进程异常退出导致内存中的日志丢失。
现象:脚本正在跑,tail -f 看不到日志。脚本报错崩溃后,最后几十条日志“失踪了”。
原因:Yii2 默认 flushInterval 和 exportInterval 均为 1000。这意味着积攒 1000 条日志才写盘。在 CLI 中,只要脚本崩溃或被 Kill,这 1000 条日志就会凭空消失。
最佳实践: 在 config/console.php 中,将这两个值设为 1(实时写入)。
修改 config/console.php:
'components' => [
'log' => [
'flushInterval' => 1, // Logger -> Target: 立即
'targets' => [
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 1, // Target -> Medium: 立即
'logVars' => [], // CLI 没必要记录 $_SERVER 等
// ... 其他配置
],
],
],
],
适用于简单的定时任务 (yii hello/index) 或临时手动执行的脚本。
使用 FileTarget 记录到 @runtime/logs/console.log。
多进程并发时(如每分钟启动一个同步脚本),没有 PID 很难区分日志来源。
'prefix' => function ($message) {
return "[" . getmypid() . "]";
},
现象:Yii::info() 只写文件,控制台一片黑,调试困难;echo 只上屏,不留档。 最佳实践:
最佳实践:
php://stdout 的 Target,方便调试。// config/console.php (可以仅在 dev 环境开启)
'targets' => [
// ... FileTarget ...
[
'class' => 'yii\log\FileTarget',
'logFile' => 'php://stdout', // 直接写到标准输出
//'categories' => ['application'], // 过滤杂音
'logVars' => [],
'exportInterval' => 1,
// 自定义格式,去掉时间戳(因为屏幕左边通常不需要太长的前缀)
'prefix' => function ($message) {
return "";
},
],
],
这是现代微服务和 12-Factor App 推荐的架构。适用于 yii queue/listen 等常驻进程。
PHP 只管“说” (Stdout),Supervisor 负责“记” (File)。
彻底解决 PHP 多进程写文件的锁争用、权限问题以及日志轮转问题。
放弃写 @runtime 目录,全部吐给标准输出。
'targets' => [
// 将所有 INFO 级别以上的日志输出标准输出
[
'class' => 'yii\log\FileTarget',
'logFile' => 'php://stdout',
'exportInterval' => 1,
'levels' => ['info', 'warning', 'error'],
'logVars' => [],
// 建议:输出 JSON 格式,方便 Supervisor 收集后被 ELK 解析
'formatMessage' => function ($message) {
return json_encode([
'time' => date('Y-m-d H:i:s'),
'level' => yii\log\Logger::getLevelName($message[1]),
'category' => $message[2],
'pid' => getmypid(),
'msg' => $message[0],
// 自动携带 Request ID (如果实现了该组件)
'trace_id' => Yii::$app->params['request_id'] ?? null,
], JSON_UNESCAPED_UNICODE);
}
],
// (可选) 错误单独走 stderr,但这在 Supervisor 中通常会被 redirect_stderr=true 合并
],
让 Supervisor 接管日志的写入、轮转和生命周期。
[program:yii-worker]
command=php /path/to/yii queue/listen
process_name=%(program_name)s_%(process_num)02d
numprocs=4
autostart=true
autorestart=true
user=www-data
; --- 日志托管 ---
redirect_stderr=true ; 合并 stderr 到 stdout
stdout_logfile=/var/log/supervisor/yii-worker.log ; 日志落盘位置
stdout_logfile_maxbytes=50MB ; 自动轮转:50MB 切分
stdout_logfile_backups=10 ; 保留最近 10 个文件
CLI 任务通常由 Web 请求触发(如异步发邮件)。为了串联日志:
Web 端 (Producer): 生成 Request ID 并放入 Job 载荷。
Yii::$app->queue->push(new Job([
'trace_id' => Yii::$app->params['request_id'],
'data' => $data
]));
CLI 端 (Consumer): 取出 trace_id 并设为当前上下文。
public function execute($queue) {
Yii::$app->params['request_id'] = $this->trace_id; // 注入上下文
Yii::info("Job started"); // 日志组件会自动读取 params['request_id']
}
Web 模式有 ErrorHandler 显示错误页,CLI 模式异常直接导致进程退出。
务必确保 console/config/main.php 正确配置了 errorHandler,配合 flushInterval=1,确保死前最后一声惨叫能被记录。
'components' => [
'errorHandler' => [
'class' => 'yii\console\ErrorHandler',
],
],
| 场景 | 写入目标 | 轮转管理 | 权限管理 |
|---|---|---|---|
| 独立脚本 | FileTarget -> .log 文件 | Yii 自带 (maxLogFiles) | 需注意 chmod,避免 root 执行后 www-data 无法写 |
| Supervisor | FileTarget -> stdout | Supervisor 自带 | 完美 (由 Supervisor 父进程管理) |
黄金法则:CLI 模式下,永远设置 flushInterval 和 exportInterval 为 1。
本文由 best 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。