yii2需通过log组件的beforeflush回调注入请求参数和session,而非logvars;须判明web应用、会话状态及敏感字段脱敏,并兼容rest/cli场景。

Yii2 中如何让异常日志自动包含请求参数和 Session
默认情况下,Yii2 的 log 组件捕获异常时只记录堆栈和错误消息,$_GET、$_POST、$_SESSION 等上下文全被丢掉了。要补上这些信息,不能靠改日志格式,得在异常触发前主动把上下文塞进日志上下文里。
关键点是:Yii 的 yii\log\Target(比如 FileTarget)支持通过 getContextMessage() 注入额外内容,但默认实现是空的;你需要重写它,或者更稳妥地——用 beforeFlush 回调动态注入当前请求快照。
- 推荐在
config/web.php的log组件配置中加'beforeFlush' => ['app\components\LogContextInjector', 'inject'],然后写一个独立类做采集 - 别在
getContextMessage()里直接读Yii::$app->session,Session 可能未开启或已关闭,先判if (Yii::$app->has('session') && Yii::$app->session->getIsActive()) -
$_FILES和大体积$_POST(如 base64 图片)别无脑记录,容易撑爆日志文件,建议只留array_keys($_POST)或加大小限制
为什么不能只靠 logVars 配置项
logVars 看起来能解决这个问题——它确实会把指定变量 dump 进日志,但有两个硬伤:
- 它只在
Application::log()被显式调用时生效,而异常是框架底层抛出并由ErrorHandler捕获的,不走这个路径 - 它记录的是变量「当时」的值,而异常可能发生在控制器动作执行中途,
$_SESSION或Yii::$app->request属性可能已被修改,不是出错瞬间的状态 - 它不区分环境,默认连
$_SERVER都打全,敏感字段(如HTTP_AUTHORIZATION)会直接泄露
Session 数据怎么安全地记进日志
Session 不是随时可读的字符串容器,尤其在 CLI 或无会话上下文的场景下直接访问会报错。必须分三步处理:
- 检查会话是否已启动:
Yii::$app->session->getIsActive(),而不是只看Yii::$app->has('session') - 避免序列化整个 session 对象(含闭包、资源等不可序列化项),应只取
Yii::$app->session->toArray(),且过滤掉__flash、_language这类框架内部键 - 对敏感字段做脱敏,比如
'user_id' => $session['user_id'], 'auth_key' => '***',不要依赖“反正日志有权限控制”这种想法
请求参数记录的性能和兼容性注意点
每次异常都完整 dump $_REQUEST 听起来方便,但实际线上容易踩坑:
- PHP 8.1+ 对超大数组的
var_export(日志默认用它)有深度限制,遇到嵌套过深的参数会截断甚至崩溃,建议用json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)替代 - RESTful 接口常以
application/json提交数据,此时$_POST为空,得从Yii::$app->request->getRawBody()读,但要注意编码和长度(避免 OOM) - 如果用了
yii\filters\Cors,预检请求(OPTIONS)也会触发日志,但没实际业务参数,需在注入逻辑里跳过Yii::$app->request->isOptions
最麻烦的其实是异步任务——console 应用里的异常根本没 request 和 session,强行读会报错。所以 LogContextInjector 必须先判断 Yii::$app instanceof \yii\web\Application 再决定采集哪些内容。











