当前位置: 首页 > news >正文

Laravel分布式全链路追踪实战

我以larevel框架做分布式全链路追踪为实例

安装必要的包

composer require jaeger/jaeger-client-php
composer require opentracing/opentracing

创建 Service Provider

php artisan make:provider TracingServiceProvider
<?php
// app/Providers/TracingServiceProvider.phpnamespace App\Providers;use Jaeger\Config;
use OpenTracing\GlobalTracer;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Log;class TracingServiceProvider extends ServiceProvider
{public function register(){$this->app->singleton('jaeger.tracer', function () {$config = new Config(['sampler' => ['type' => 'const','param' => true,],'logging' => true,'local_agent' => ['reporting_host' => env('JAEGER_AGENT_HOST', 'localhost'),'reporting_port' => env('JAEGER_AGENT_PORT', 6831),],],env('APP_NAME', 'laravel-app'));return $config->initializeTracer();});// 设置全局 tracerGlobalTracer::set($this->app->make('jaeger.tracer'));}public function boot(){//}
}

注册 Service Provider

// config/app.php
'providers' => [// ...App\Providers\TracingServiceProvider::class,
],

创建中间件

php artisan make:middleware TracingMiddleware
<?php
// app/Http/Middleware/TracingMiddleware.phpnamespace App\Http\Middleware;use Closure;
use OpenTracing\GlobalTracer;
use OpenTracing\Tags;
use Illuminate\Http\Request;class TracingMiddleware
{public function handle(Request $request, Closure $next){$tracer = GlobalTracer::get();// 从请求头中提取追踪上下文$spanContext = $tracer->extract(\OpenTracing\Formats\HTTP_HEADERS,$request->headers->all());$scope = $tracer->startActiveSpan('http.request',['child_of' => $spanContext,'tags' => [Tags\HTTP_METHOD => $request->method(),Tags\HTTP_URL => $request->fullUrl(),'http.host' => $request->getHost(),'http.path' => $request->path(),'http.query' => $request->getQueryString() ?: '','http.user_agent' => $request->userAgent(),'http.client_ip' => $request->ip(),]]);// 将 span 存储到请求中,供后续使用$request->attributes->set('tracing_scope', $scope);try {$response = $next($request);$scope->getSpan()->setTag(Tags\HTTP_STATUS_CODE, $response->getStatusCode());return $response;} catch (\Exception $e) {$scope->getSpan()->setTag(Tags\ERROR, true);$scope->getSpan()->log(['event' => 'error','error.kind' => get_class($e),'message' => $e->getMessage(),'stack' => $e->getTraceAsString(),]);throw $e;}}public function terminate($request, $response){if ($request->attributes->has('tracing_scope')) {$scope = $request->attributes->get('tracing_scope');$scope->close();}}
}

注册中间件

// app/Http/Kernel.php
protected $middleware = [// ...\App\Http\Middleware\TracingMiddleware::class,
];

数据库查询追踪

// app/Providers/AppServiceProvider.phpnamespace App\Providers;use Illuminate\Support\ServiceProvider;
use OpenTracing\GlobalTracer;
use Illuminate\Support\Facades\DB;class AppServiceProvider extends ServiceProvider
{public function boot(){if (config('tracing.enabled', false)) {DB::listen(function ($query) {$tracer = GlobalTracer::get();$scope = $tracer->startActiveSpan('db.query', ['tags' => ['db.system' => 'mysql','db.statement' => $query->sql,'db.query.bindings' => json_encode($query->bindings),'db.query.time' => $query->time . 'ms',]]);$scope->close();});}}
}

HTTP 客户端追踪(Guzzle)

// app/Services/TracingHttpClient.phpnamespace App\Services;use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use OpenTracing\GlobalTracer;
use OpenTracing\Formats;
use OpenTracing\Tags;class TracingHttpClient
{public static function create(): Client{$stack = HandlerStack::create();$stack->push(self::createTracingMiddleware());return new Client(['handler' => $stack,'timeout' => 30,]);}private static function createTracingMiddleware(): callable{return function (callable $handler) {return function ($request, array $options) use ($handler) {$tracer = GlobalTracer::get();$scope = $tracer->startActiveSpan('http.client.request', ['tags' => [Tags\HTTP_METHOD => $request->getMethod(),Tags\HTTP_URL => (string) $request->getUri(),'http.target' => $request->getRequestTarget(),]]);// 注入追踪头$tracer->inject($scope->getSpan()->getContext(),Formats\HTTP_HEADERS,$request->getHeaders());return $handler($request, $options)->then(function ($response) use ($scope) {$scope->getSpan()->setTag(Tags\HTTP_STATUS_CODE, $response->getStatusCode());$scope->close();return $response;},function ($reason) use ($scope) {$scope->getSpan()->setTag(Tags\ERROR, true);$scope->getSpan()->log(['error' => $reason]);$scope->close();throw $reason;});};};}
}

队列任务追踪

// app/Jobs/TracedJob.phpnamespace App\Jobs;use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use OpenTracing\GlobalTracer;
use OpenTracing\Tags;class TracedJob implements ShouldQueue
{use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;protected $spanContext;public function __construct(array $spanContext = null){$this->spanContext = $spanContext;}public function handle(){$tracer = GlobalTracer::get();$scope = $tracer->startActiveSpan('job.process', ['child_of' => $this->spanContext,'tags' => ['job.name' => static::class,'job.queue' => $this->queue,'job.attempts' => $this->attempts(),]]);try {$this->processJob();$scope->close();} catch (\Exception $e) {$scope->getSpan()->setTag(Tags\ERROR, true);$scope->getSpan()->log(['event' => 'error','error.kind' => get_class($e),'message' => $e->getMessage(),]);$scope->close();throw $e;}}protected function processJob(){// 实际的作业处理逻辑}// 在分发作业时保存追踪上下文public static function dispatchWithTracing(){$tracer = GlobalTracer::get();$spanContext = $tracer->getActiveSpan()?->getContext();return new static($spanContext);}
}

配置文件

php artisan vendor:publish --provider="App\Providers\TracingServiceProvider"
// config/tracing.phpreturn ['enabled' => env('TRACING_ENABLED', true),'service_name' => env('TRACING_SERVICE_NAME', env('APP_NAME', 'laravel-app')),'jaeger' => ['agent_host' => env('JAEGER_AGENT_HOST', 'localhost'),'agent_port' => env('JAEGER_AGENT_PORT', 6831),],'sampler' => ['type' => env('TRACING_SAMPLER_TYPE', 'const'),'param' => env('TRACING_SAMPLER_PARAM', true),],'tags' => ['environment' => env('APP_ENV', 'production'),'version' => env('APP_VERSION', '1.0.0'),],
];

.env 配置

TRACING_ENABLED=true
TRACING_SERVICE_NAME=my-laravel-app
JAEGER_AGENT_HOST=localhost
JAEGER_AGENT_PORT=6831
TRACING_SAMPLER_TYPE=const
TRACING_SAMPLER_PARAM=true

http请求的使用示例

// 在控制器中使用
namespace App\Http\Controllers;use App\Services\TracingHttpClient;
use OpenTracing\GlobalTracer;
use OpenTracing\Tags;class UserController extends Controller
{public function show($id){$tracer = GlobalTracer::get();$scope = $tracer->startActiveSpan('user.controller.show', ['tags' => ['user.id' => $id,]]);try {// 调用外部服务$client = TracingHttpClient::create();$response = $client->get('https://api.example.com/users/' . $id);$user = json_decode($response->getBody(), true);$scope->getSpan()->log(['message' => 'User fetched successfully']);return response()->json($user);} catch (\Exception $e) {$scope->getSpan()->setTag(Tags\ERROR, true);$scope->getSpan()->log(['error' => $e->getMessage()]);throw $e;} finally {$scope->close();}}
}

http://www.xdnf.cn/news/1344205.html

相关文章:

  • 【机器学习深度学习】LMDeploy的分布式推理实现
  • selenium爬虫
  • 布隆过滤器:用微小的空间代价换取高效的“可能存在”判定
  • TCP/UDP详解(一)
  • 微服务的编程测评系统14-C端题目列表功能-个人中心
  • Redis面试精讲 Day 27:Redis 7.0/8.0新特性深度解析
  • 高通Camx相机dump yuv和raw图的抓取方式和查看
  • 【iOS】YYModel第三方库源码
  • 笔试——Day46
  • 恢复性测试:定义、重要性及实施方法
  • 深入解析CNAME记录:域名管理的隐形枢纽
  • 几个element-plus的UI,及环境配置
  • 三格电子——ModbusTCP 转 Profinet 主站网关应用实例
  • 【TrOCR】根据任务特性设计词表vocab.json
  • RabbitMQ面试精讲 Day 27:常见故障排查与分析
  • 【数据结构C语言】顺序表
  • 四十一、【高级特性篇】API 文档驱动:OpenAPI/Swagger 一键导入测试用例
  • Design Compiler:层次模型(Block Abstraction)的简介
  • memcmp 函数的使用及其模拟实现
  • 数学建模--Topsis
  • 分布式与微服务
  • [特殊字符] 潜入深渊:探索 Linux 内核源码的奇幻之旅与生存指南
  • LeetCode Hot 100 第一天
  • 相机曝光调节与自动曝光控制详解
  • AI适老服务暖人心:AI适老机顶盒破数字鸿沟、毫米波雷达护独居安全,银发生活新保障
  • 初识数据结构——Map和Set:哈希表与二叉搜索树的魔法对决
  • 车载以太网SOME/IP协议:面向服务的汽车通信技术详解
  • python-对图片中的人体换背景色
  • Java面试宝典:Redis底层原理(持久化+分布式锁)
  • 机器学习-线性回归