在 report() 中通过 request() 或 app('request') 获取请求实例,优先使用 $request->ip() 和 $request->header('user-agent') 等关键字段,注意队列/命令行场景下 request() 为 null,需判空;自定义异常可预埋上下文避免依赖 request(),并确保生产环境日志通道显式启用。

直接在 report() 方法里加请求上下文,是最简单也最可靠的方案。Laravel 的 Handler 类默认接收 $request 实例(Laravel 8+),但很多人没意识到它默认不传入 report(),必须手动注入或从容器取。
report() 方法如何获取当前 Request 实例
Laravel 的 report() 方法签名是 public function report(Throwable $exception),不带 $request。不能直接用 $request->headers 或 $request->cookies —— 那会报错。
- 正确做法:在
report()内部通过app('request')或request()辅助函数获取当前请求实例 - 注意:仅在 HTTP 请求生命周期中有效;队列任务、命令行调用等场景下
request()返回 null,需先判断 - 更稳妥写法:
$request = app('request', []); if ($request && $request->hasSession()) { ... }
记录请求头、Cookie 和客户端 IP 的典型写法
重点不是“能不能记”,而是“记哪些字段才真正有用”。生产环境里,User-Agent、X-Forwarded-For、Cookie(脱敏后)和 session_id 最常用于复现问题。
- 只记录敏感 Cookie 名称(如
laravel_session),不记录值;可用$request->cookies->has('laravel_session')判断存在性 - 用
$request->header('user-agent', 'unknown')获取 UA,避免空值导致日志解析失败 - IP 地址优先用
$request->ip(),它已自动处理X-Forwarded-For和代理信任配置 - 避免直接 dump 整个
$request->headers,它包含大量冗余字段(如accept-encoding),增加日志体积且无排查价值
自定义异常类中如何预埋上下文
如果你抛出的是自定义异常(比如 InsufficientBalanceException),可以在构造时把关键上下文存进异常属性,而不是等到 report() 才去查 request()。
- 在异常类里加
protected $context = [];,构造时传入request()->ip()、request()->header('user-agent')等 -
report()中可直接读$exception->getContext(),避免在异步/队列中因request()不可用而丢失信息 - 注意:不要在异常构造时调用
$request->cookie('xxx'),因为 Cookie 值可能被加密或已过期,解密失败会抛新异常,掩盖原始错误
最容易被忽略的一点:APP_ENV=testing 或 APP_DEBUG=true 时,Laravel 默认跳过部分日志通道(比如 stack 里的 daily),导致你本地测试能看到上下文,上线后却完全没记录——务必在生产配置中显式启用目标日志通道,并用 Log::channel('xxx')->error() 替代默认 Log::error() 来确保落盘。











