队列日志必须用显式 json_encode() 输出结构化 JSON,固定字段 job/id/attempts/runtime_ms/status,避免自动序列化和敏感数据;通过 JobProcessing 事件或任务类自身获取元信息;强制单行并过滤非 JSON 行以保障 ELK 分析可靠性。

队列任务执行日志怎么打才方便 grep 和 ELK 分析
直接在 handle() 里用 Log::info() 打字符串日志,后期根本没法查「哪个任务失败了」「重试了几次」「耗时多少」。结构化不是为了好看,是为后续用 jq 或 Kibana 做聚合统计留活路。
- 必须用
json_encode()显式构造 JSON 字符串,别依赖 Laravel 日志通道自动序列化 —— 它会把对象转成不可读的"object: IlluminateBusPendingDispatch"这种东西 - 关键字段建议固定:
"job"(任务类名)、"id"(任务 ID,可用$this->job->getJobId())、"attempts"、"runtime_ms"、"status"(success / failed) - 避免在日志里塞完整请求体或用户敏感数据,结构化不等于无脑 dump —— 该脱敏的脱敏,该截断的截断(比如
substr($payload, 0, 256))
Laravel 队列监听器里怎么拿到任务元信息
很多人卡在这步:想记重试次数,但 $this->attempts() 在 handle() 里能用,在日志中间件或事件监听器里反而拿不到。真正稳定可取的来源只有两个:
- 任务类自身:在
__construct()里存$this->jobId = uniqid('job_', true),或用data_get($this, 'job') instanceof IlluminateContractsQueueJob判断是否已绑定运行时上下文 - 使用
IlluminateQueueEventsJobProcessing事件:它带$event->job->attempts()、$event->job->payload(),且比handle()更早触发,适合做前置日志埋点 - 别碰
JobProcessed或JobFailed的$event->job->resolveName()—— 某些驱动(如 database)下这个方法会抛BadMethodCallException
JSON 日志写进 storage/logs/ 后为什么被截断或乱码
默认 daily 日志通道用 StreamHandler,它对单行长度没限制,但某些系统(比如 Docker 容器里跑的 rsyslog)或日志采集 agent(Filebeat 默认行长度 10MB)会主动切行。结果就是一条 JSON 被切成两半,jq 直接报错 parse error: Invalid string: control character。
- 强制单行:在日志内容里用
str_replace([" ", " "], '\n', $json)替换换行符,再套一层json_encode()保证合法 - 改用
Single日志通道并配置max_files=0,避开 daily 的文件轮转逻辑干扰 JSON 行完整性 - 更稳的做法:不走 Laravel 日志系统,直接
file_put_contents(storage_path('logs/queue.json'), $json . " ", FILE_APPEND | LOCK_EX)—— 绕过所有 Handler 的编码/格式化逻辑
用 Logstash 或 Fluentd 收集时字段提取总失败
不是配置写错了,大概率是日志里混了非 JSON 行(比如 PHP Warning、Composer autoload 错误、甚至 .env 加载失败提示),导致整个日志流解析中断。结构化日志的前提是「纯」。
- 在队列 worker 启动时加
ini_set('log_errors', 'Off'),关掉 PHP 自己往 stderr 写的杂音 - 在
config/logging.php里给队列专用通道加'level' => 'debug',但排除error级别 —— 把错误单独路由到另一个文件,别和结构化日志搅一起 - Logstash filter 里必须加
if [message] !~ /^{s*"/ { drop {} },先筛掉非 JSON 行,不然一整批都 parse 不了
JSON 结构本身很简单,难的是让每条记录从产生到入库全程不被中间环节污染。只要有一处换行、一个未转义双引号、一行非 JSON 的 warning,下游分析就全垮。这事得盯住源头,而不是指望 Logstash 补救。


















