推荐使用自定义中间件记录API请求日志,并配合独立的api日志channel;错误日志需确保Handler::report()未忽略ValidationException等异常,敏感字段须过滤,日志应采用JSON格式便于结构化分析。

怎么让 Laravel API 自动记录请求和错误日志
默认情况下,Laravel 的 log 配置只记录错误和异常,API 请求(比如每个 POST /api/users)不会被自动记下来。想看到谁在什么时候调用了哪个接口、传了什么参数、返回了什么状态,得自己加中间件或重写日志通道。
推荐用中间件 + Log::info() 记录请求,用异常处理器捕获错误——这样既不干扰原有逻辑,又能控制粒度。
- 别直接改
App\Exceptions\Handler::report()来记所有请求,它只处理抛出的异常,漏掉 200 成功响应 - 避免在控制器里每处都写
Log::info(),维护成本高,且容易漏掉验证失败、422 等非异常但需追踪的情况 - 注意敏感字段:
$request->all()可能含密码、token,记录前务必用array_except()或手动过滤password、token、authorization等键
Laravel 10+ 中如何写一个轻量请求日志中间件
中间件是唯一能稳定拦截每次 API 请求的地方,且可按路由分组启用(比如只对 api 中间件组生效)。
执行 php artisan make:middleware LogApiRequest,然后在 handle() 里写:
public function handle(Request $request, Closure $next)
{
$startTime = microtime(true);
$response = $next($request);
$duration = round((microtime(true) - $startTime) * 1000);
<pre class="brush:php;toolbar:false;">// 过滤敏感字段
$loggedInput = Arr::except($request->all(), ['password', 'token', 'remember_token']);
Log::channel('api')->info('API Request', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'ip' => $request->ip(),
'status' => $response->getStatusCode(),
'duration_ms' => $duration,
'input' => $loggedInput,
'user_id' => $request->user()?->id,
]);
return $response;}
- 必须用独立日志 channel(如
api),否则会和错误日志混在一起,grep 查找困难 - 别在
$response后再读$request->json()或$request->getContent(),部分请求体可能已被消费,返回空字符串 - 如果用 Sanctum / Passport,
$request->user()在未认证时为 null,别直接取id,用空合并$request->user()?->id
错误日志为什么没记录 401/403/422 这类 HTTP 错误
这些不是 PHP 异常,而是 Laravel 主动返回的响应(ResponseFactory::json(..., 401)),Handler::report() 根本不会触发。它们安静地流走了,日志里只有空白。
真正要抓的是底层抛出的异常:比如 AuthenticationException、AuthorizationException、ValidationException。这些会在 Handler::report() 里被捕获。
- 确保
App\Exceptions\Handler::report()没有把ValidationException之类 silently 忽略掉(检查是否有if ($exception instanceof ValidationException) { return; }) - 自定义 422 响应时,别用
response()->json(..., 422)绕过异常机制;应 throw newValidationException($validator) - 401 和 403 默认由 Laravel 的
Authenticate和Authorize中间件抛出对应异常,只要没重写中间件逻辑,就会进日志
log channel 配置错会导致日志写不进文件或写到错地方
API 日志建议单独配一个 channel,比如叫 api,类型设为 daily,避免和 stack 或 single 混用导致轮转混乱或权限问题。
在 config/logging.php 里加:
'api' => [
'driver' => 'daily',
'path' => storage_path('logs/api.log'),
'level' => 'info',
'days' => 14,
],- 路径必须是绝对路径,
storage_path()是必须的,别写相对路径如logs/api.log - 如果用
stderr或syslog,本地开发可能看不到日志,部署时也要确认容器或服务器是否支持 - 权限问题常见于 Docker 或 Forge 部署:确保
storage/logs/目录对 web 用户(如 www-data)可写,否则日志静默失败
最麻烦的其实是日志字段设计——比如把 url 和 input 全塞进一条 log line,后续用 grep 或 ELK 做分析时根本没法结构化解析。真要长期用,得用 JSON 格式写入,而不是默认的单行文本。










