必须用monolog的context传业务数据、extra传技术元数据,并配置lineformatter显式输出二者;手动字符串拼接会导致检索失效、敏感信息泄露,且context严禁含password等敏感字段。

PHP框架中日志信息拼接混乱、上下文缺失、排查困难,是因为没用好Monolog的context和extra参数,也没配置结构化formatter——直接字符串拼接不仅难检索,还会埋下敏感信息泄露风险。
用context传结构化上下文,避免手拼字符串
在记录日志时,把业务数据放进context数组,而不是用"用户ID:".$uid." 登录失败"这种硬拼方式。
调用
Log::info('Login failed', ['user_id' => $uid, 'ip' => $request->ip(), 'agent' => $request->userAgent()])
<p>这一步必须用数组传参,Monolog会自动序列化并保留键值关系;如果手动拼接成字符串,搜索<code>user_id:12345</code></p>就失效了,grep也捞不到结构字段。
【context里禁止传敏感字段如password、token、银行卡号】
用extra补充运行时元数据,不污染业务逻辑
Monolog的extra字段专用于注入非业务但对排错关键的信息,比如请求ID、链路追踪号、服务器主机名。
方法一:全局Processor注入(推荐)
在Logger初始化阶段添加new IntrospectionProcessor()和new WebProcessor(),自动注入行号、文件、URL、$_SERVER等。
方法二:单条日志动态追加$log->info('Order created', ['order_id' => 9876], ['trace_id' => $this->traceId, 'env' => APP_ENV]);
注意:extra内容不会被格式化器默认输出,必须在Formatter中显式启用include_extra选项,否则白写了。
定制LineFormatter,控制日志字段顺序与可读性
第一步:实例化LineFormatter,指定时间格式、是否显示通道名、是否展开context/extra$formatter = new LineFormatter( "[%datetime%] [%channel%] [%level_name%] %message% %context% %extra%\n", "Y-m-d H:i:s", true, true );
第二步:将formatter绑定到Handler
$handler = new StreamHandler('app.log');<br>
$handler->setFormatter($formatter);<br>
$log->pushHandler($handler);
第三步:验证输出效果——你会看到类似这样的一行:
[2026-08-11 15:16:22] [auth] [ERROR] Login failed {"user_id":10086,"ip":"192.168.1.100"} {"trace_id":"abc123","env":"prod"}
这一步不能跳过格式器设置,否则context和extra内容会被丢弃或转成无意义的Array字样。
在Laravel中复用已有Log Facade,但覆盖默认Formatter
打开config/logging.php,找到'stack'或自定义通道的配置块。
在handlers数组内对应stream或daily处理器下,添加'formatter' => \Monolog\Formatter\LineFormatter::class。
再往下加'formatter_with_context' => true和'formatter_include_extra' => true两项——这是Laravel 9+才支持的原生扩展点,低于此版本需手动重写Handler类。
最后执行php artisan config:clear,否则新配置不生效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











