失业两个月找存在感系列——几行代码轻松实现laravel链式追踪,一分钟快速排查系统问题
YY理解
所谓的链式追踪,并没有多高大尚,简单的可以理解为在一次请求中,生成一个链路请求trace_id,在整个请求过程中记录的日志都包含这个trace_id,对于拆分系统的微服务而言,可以在调用其他服务的时候把这个trace_id传入调用系统,这样整个请求生命周期中一直都有这个标识,可以顺藤摸瓜,问题有迹可循
优点
能快速的通过trace_id 查找完整的请求链路日志,通过命令或者elk方式只需要这个ID就能搜索出所有线索日志,进而快速排查问题
laravel代码实现
思路
laravel通常是运行在php-fpm模式下,请求都是在一个进程中完成的,所以本身就是一条从开始到结束的直线。只需要我们在请求最初时候产生这个trace_id ,然后在后续的代码处理记录日志的时候只要把这个ID加上即可。
laravel实现思路
对于laravel而言,可以使用前置中间件和后置中间件以及重新log记录日志方式便可以实现
laravel代码实现
首先
kernel.php
注册中间件/** * The application's route middleware groups. * * @var array */protected $middlewareGroups = [ 'gptapp' => [ \App\Http\Middleware\RequestBefore::class, \App\Http\Middleware\ResponseAfter::class, ], ];
编写请求之前前置中间件
RequestBefore
,在请求到业务逻辑之前进行生成trace_id 保存到request 对象上class RequestBefore { public function handle(Request $request, Closure $next) { //没有则生成唯一请求ID if (! $request->header('Request-Id')) { $requestId = (string)md5( uniqid() . time()); $request->headers->set('Request-Id', $requestId); } return $next($request); } }
封装带有trace_id的日志记录方法
Log
, laravel8以后有自带上下文的日志记录方法(此步骤可以省略)class extends Log { static function info ($arr) { //加上唯一ID $arr['request_id'] = request()->headers->get('Request-Id', $requestId); //调用laravel log门面写日志 SysLog::info(json_encode($arr)); } }
编写请求响应之后的后置中间件
ResponseAfter
,使用带有trace_id 的日志记录方法进行日志保存class ResponseAfter { public function handle(Request $request, Closure $next) { $response = $next($request); // 执行操作 Log::info([ 'request' => [ 'client_ip' => $request->getClientIp(), 'method' => $request->getMethod(), 'route' => $request->getRequestUri(), 'content_type' => $request->getContentType(), 'content' => $request->all(), 'headers' => $request->headers->all(), ], 'response' => [ 'headers' => $response->headers->all(), 'contents' => $response->getContent(), ], ]); return $response; } }
总结
php是世界上最好的编程语言,其他编程语言能做的,php也能!!!
本作品采用《CC 协议》,转载必须注明作者和本文链接
高认可度评论:
有点麻烦,直接
withContext
或者shareContext
赞,不错的方案 :+1:
欢迎大佬们给出更好的方案
如果是fpm的话一个静态变量就可以搞定。
laravel 的 这个 AppServiceProvider 里面加上这个就行。
其实最早的时候用其他的也是类似。fpm不通请求都是隔离的。这个方案就可以快速实现。
有点麻烦,直接
withContext
或者shareContext
看起来还不错的样子。
大佬目前找到工作了吗
请问这种追踪是只能用于微服务架构对吗?
我这边想处理的链追踪是分布式架构的,就是后端有多个服务器
用户第一个请求在 IP1,第二个请求在 IP2 .....
期望在查询日志的时候,可以把某一个用户的请求全部查询出来,用这个方式是不是不适用?
我之前也写过一个 github.com/kphcdr/laravel-trace-id 公司的项目一直在用
队列能用吗?
这种只是追日志吧 真链路追踪还得是这种