bilfeldt / laravel-correlation-id
在 Laravel 应用中处理 Request-ID 和 Correlation-ID
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- illuminate/contracts: ^10.0 || ^11.0
Requires (Dev)
- nunomaduro/collision: ^7.8 || ^8.0
- orchestra/testbench: ^8.0 || ^9.0
- phpunit/phpunit: ^10.0
README
通过中间件创建请求的 Correlation-IDs,并将这个全局唯一的 Correlation-ID
以及任何用户提供的 Request-ID
传递给全局日志上下文。
动机
每个请求都应该有一个唯一的 Correlation ID,这个 ID 可以唯一确定用户交互。然后,应该将这个 Correlation ID 添加到所有日志条目作为上下文,错误报告以及任何子系统(如外部 API 调用或排队作业)。这样做可以使跟踪特定用户请求的相关接触点成为可能。更多信息请参阅 这里。
客户端也可以提供一个 Request ID,良好的实践是在响应中返回它并将其与 Correlation ID 关联。更多信息请参阅 这里。
安装
您可以通过 composer 安装此包
composer require bilfeldt/laravel-correlation-id
将 Correlation ID 分配给请求
注意
理想情况下,唯一的 Correlation ID 应该在您的基础设施的第一个接触点处创建,例如初始服务器,可能是负载均衡器
由于在服务器级别创建 Correlation ID 可能比较复杂,但在 Laravel 中使用中间件则非常简单。此包提供了一个创建 Correlation ID 并将其作为头部 Correlation-ID
以及响应头部附加到请求上的中间件。您应该在基础设施的第一个接触点处分配 correlation id,或者在 app/Http/Kernel.php
类的 $middleware
属性中全局注册 CorrelationIdMiddleware
中间件作为第一个中间件。
// app/Http/Kernel.php /** * The application's global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array<int, class-string|string> */ protected $middleware = [ \Bilfeldt\CorrelationId\Middleware\CorrelationIdMiddleware::class, // <!-- Add this globally as the first toutchpoint // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ];
将 Request ID 分配给响应
如果客户端在请求头部中提供了 Request ID,则将此复制到响应头部是一种良好的实践。这可以通过在 app/Http/Kernel.php
类的 $middleware
属性中全局添加 ClientRequestIdMiddleware
中间件来完成。
// app/Http/Kernel.php /** * The application's global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array<int, class-string|string> */ protected $middleware = [ \Bilfeldt\CorrelationId\Middleware\CorrelationIdMiddleware::class, \Bilfeldt\CorrelationId\Middleware\ClientRequestIdMiddleware::class, // <!-- Add this globally // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ];
用法
此包在 Illuminate\Http\Request
类上注册了一些宏
$request->getCorrelationId(); // UUID or null if not assigned $request->getClientRequestId(); // The `Request-ID` header if provided by the client $request->getUniqueId(); // Unique UUID for each request: 94d0e2d6-4cc6-449c-9140-80bca47d29b4
添加全局日志上下文
可以添加 Correlation ID 和 Request ID 到全局日志上下文,以便添加到日志中的任何内容都将自动附加 ID 作为上下文。
建议在将它们分配给请求后立即将它们添加到日志上下文中。这可以通过在 app/Http/Kernel.php
类的 $middleware
属性中全局注册 LogContextMiddleware
中间件来实现。
// app/Http/Kernel.php /** * The application's global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array<int, class-string|string> */ protected $middleware = [ \Bilfeldt\CorrelationId\Middleware\CorrelationIdMiddleware::class, \Bilfeldt\CorrelationId\Middleware\ClientRequestIdMiddleware::class, \Bilfeldt\CorrelationId\Middleware\LogContextMiddleware::class, // <!-- Add this globally AFTER assigning Correlation ID and Request ID. // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ];
将全局上下文添加到错误报告
可以将 Correlation ID 和 Request ID 添加到全局错误报告上下文中,以便在添加这些信息后,任何错误报告都将自动附加 ID 作为上下文。
如果变量已经添加到日志上下文,则建议将所有全局日志上下文合并到错误报告上下文中,覆盖应用程序的 App\Exceptions\Handler
的 context
方法。
// app/Exceptions/Handler.php /** * Get the default context variables for logging. * * @return array<string, mixed> */ protected function context(): array { return array_merge(parent::context(), $this->getGlobalLogContext()); } private function getGlobalLogContext(): array { try { return Log::sharedContext(); } catch (\Throwable $e) { return []; } }
或者如果您不想共享所有全局日志上下文,只需使用上面描述的宏从 request()
辅助函数中获取 ID
// app/Exceptions/Handler.php /** * Get the default context variables for logging. * * @return array<string, mixed> */ protected function context(): array { return array_merge(parent::context(), [ 'correlation_id' => request()->getCorrelationId(), 'request_id' => request()->getUniqueId(), ]); }
将关联 ID 和请求 ID 传递到队列作业
该包确保将 关联 ID 和 请求 ID 传递到队列作业的负载中,可以使用 $job->payload()['data']
再次检索。
在队列作业开始处理之前,我们从负载中提取 关联 ID 和 请求 ID 并将这些设置在 Illuminate\Http\Request
实例上,这样任何后续的作业如果被调度也将包含它们。
测试
composer test
变更日志
请参阅变更日志获取最近更改的更多信息。
贡献
请参阅贡献指南获取详细信息。
安全漏洞
请查阅我们的安全策略了解如何报告安全漏洞。
鸣谢
- Anders Bilfeldt
- James Brooks:感谢他在博客中关于如何将额外数据注入 Laravel 队列作业的文章。
- 所有贡献者
许可证
MIT 许可证 (MIT)。请参阅许可证文件获取更多信息。