码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071

代码地址:https://github.com/why444216978/opentracing-php-client

说点废话

之前写过一个GoLang版本的opentracing客户端实现,由于部门大部分服务还是用PHP实现的,所以打算用PHP实现一个基于jaeger的客户端。

GoLang版本中间件:https://success.blog.csdn.net/article/details/104100597

参考文档和开源组件

opentracing文档:https://wu-sheng.gitbooks.io/opentracing-io/content/pages/spec.html

opentracing-php:https://github.com/opentracing/opentracing-php

jaeger-php:https://github.com/jukylin/jaeger-php

使用方法

原理还是比较容易理解的,看我上面贴的文档手册就好了,为了让大佬(白嫖党)们快速掌握,应用到项目中,下面会直接贴代码。过程中也踩了不少坑,组件都文档描述也不全面,最终还是根据Test代码实现,一步步追踪源码才大概搞明白客户端的使用。

1、安装依赖

composer.json

{"minimum-stability": "dev","require":           {"jukylin/jaeger-php" : "^2.0","opentracing/opentracing":"1.0.0-beta5"}
}
composer install

2、封装

curl客户端:

<?php
if (!function_exists('getCurlCh')) {function getCurlCh(&$url, $data = array(), $header = array(), $method = 'POST', $timeout = 2, $others = array(), $ch = null){if (empty($ch)) {$ch = curl_init();}curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_ENCODING, '');/*** 设置post信息*/if ('POST' === strtoupper($method)) {if (is_array($data)) {curl_setopt($ch, CURLOPT_POST, count($data));} else {curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);curl_setopt($ch, CURLOPT_POST, 1);}curl_setopt($ch, CURLOPT_POSTFIELDS, $data);}if ('DELETE' === strtoupper($method)) {curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');curl_setopt($ch, CURLOPT_POSTFIELDS, $data);}/*** 设置超时时间*/curl_setopt($ch, CURLOPT_TIMEOUT_MS, intval($timeout * 1000));/*** 设置header参数*/if (!empty($header) && is_array($header)) {$tmp = array();foreach ($header as $key => $value) {$tmp[] = trim($key) . ': ' . trim($value);}curl_setopt($ch, CURLOPT_HTTPHEADER, $tmp);}/*** 设置其它信息*/if (is_array($others) && !empty($others)) {foreach ($others as $key => $value) {curl_setopt($ch, $key, $value);}}return $ch;}
}if (!function_exists('curlSend')) {function curlSend($url, $data = array(), $header = array(), $method = 'POST', $timeout = 5, $others = array(), $error = true){$ch    = getCurlCh($url, $data, $header, $method, $timeout, $others);$ret   = curl_exec($ch);$errno = curl_errno($ch);$res   = curl_getinfo($ch);curl_close($ch);$result  = array('ret' => $ret, 'errno' => $errno, 'res' => $res);return $result;}
}

注入函数:

<?php
$autoload = './vendor/autoload.php';
if (file_exists($autoload)) {require_once $autoload;
}use Jaeger\Config;
use OpenTracing\Formats;
use OpenTracing\Reference;class JaegerInject
{protected $dsn = '127.0.0.1:6831';protected $serviceName;protected $spanList = [];protected $client;protected $tracer;public function __construct($serviceName = 'test'){$this->serviceName = $serviceName;unset($_SERVER['argv']);$this->client = Config::getInstance();$this->client->gen128bit();$this->client::$propagator = Jaeger\Constants\PROPAGATOR_JAEGER;$this->tracer = $this->client->initTracer($this->serviceName, $this->dsn);}public function getSpanName() :string{return explode('?', $_SERVER['REQUEST_URI'])[0];}public function start(string $spanName){$parentContext = $this->tracer->extract(Formats\TEXT_MAP, $this->getAllHeaders());if (!$parentContext) {$span = $this->tracer->startSpan($spanName);} else {$span = $this->tracer->startSpan($spanName, ['references' => [Reference::create(Reference::FOLLOWS_FROM, $parentContext),Reference::create(Reference::CHILD_OF, $parentContext)]]);}$this->spanList[$spanName] = ['current_span'   => $span,'parent_context' => $parentContext,];}public function inject(string $spanName) :array{$info = $this->spanList[$spanName];$span = $info['current_span'];$injectHeaders = [];$this->tracer->inject($span->getContext(), Formats\TEXT_MAP, $injectHeaders);return $injectHeaders;}public function finish(string $spanName, array $spanList = []){$info = $this->spanList[$spanName];$span = $info['current_span'];$parentContext = $info['parent_context'];$span->setTag('parent', $parentContext ? $parentContext->spanIdToString() : '');foreach($spanList ?: [] as $k => $v){$span->setTag($k, $v);}$span->finish();}private function getAllHeaders(){$headers = array();$copy_server = array('CONTENT_TYPE'   => 'Content-Type','CONTENT_LENGTH' => 'Content-Length','CONTENT_MD5'    => 'Content-Md5',);foreach ($_SERVER as $key => $value) {if (substr($key, 0, 5) === 'HTTP_') {$key = substr($key, 5);if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));$headers[$key] = $value;}} elseif (isset($copy_server[$key])) {$headers[$copy_server[$key]] = $value;}}if (!isset($headers['Authorization'])) {if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];} elseif (isset($_SERVER['PHP_AUTH_USER'])) {$basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';$headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);} elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {$headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];}}return $headers;}public function __destruct(){$this->client->flush();}
}

3、试验PHP客户端

启动jaeger(使用教程):

./jaeger-all-in-one

opentracing.php

<?php
require_once './inject.php';
require_once './curl.php';$jaeger = new JaegerInject();$spanName = $jaeger->getSpanName();
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);$method = 'GET';
$url = 'http://localhost:9999/opentracing1.php';
$res = curlSend($url, [], $injectHeaders, 'GET');$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);

opentracing1.php

<?php
require_once './inject.php';
require_once './curl.php';$jaeger = new JaegerInject();$spanName = $jaeger->getSpanName();
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$method = 'GET';
$url = 'http://localhost:9999/opentracing2.php';
$res = curlSend($url, [], $injectHeaders, 'GET');
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);$spanName = $jaeger->getSpanName();
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$method = 'GET';
$url = 'http://localhost:9999/opentracing2.php';
$res = curlSend($url, [], $injectHeaders, 'GET');
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);

opentracing2.php

<?php
require_once './inject.php';
require_once './curl.php';$jaeger = new JaegerInject();$spanName = $jaeger->getSpanName();
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$method = 'GET';
$url = 'https://www.baidu.com';
$res = curlSend($url, [], $injectHeaders, 'GET');
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);

注意:公司各个服务线都有统一标准,所以默认下游服务都会自己记录span,正常来说这里请求baidu下游应该还有一个baidu的span。看我们第二个例子调用gin-api就能看明白。

分成三个rpc服务:

  1. 入口为 opentracing.php,调用了 opentracing1.php
  2. opentracing1.php 调用了2次 opentracing2.php 服务
  3. opentracing2.php 调用 www.baidu.com

调用:GET localhost/opentracing.php

查看 jaeger 链路:

4、启动 go 服务,试验双语言客户端服务链路(GoLang中间件实现)

[why@localhost] ~/Desktop/go/gin-api$go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.- using env:   export GIN_MODE=release- using code:  gin.SetMode(gin.ReleaseMode)[GIN-debug] GET    /ping                     --> gin-frame/controllers/ping.Ping (6 handlers)
[GIN-debug] GET    /test/rpc                 --> gin-frame/controllers/opentracing.Rpc (6 handlers)
[GIN-debug] GET    /origin/first_origin_

修改 opentracing2.php 代码:

<?php
require_once './inject.php';
require_once './curl.php';$injectHeaders = injectOpenTracing('test-opentracing');
$method = 'GET';
$url = '127.0.0.1:777/test/rpc';
$res = curlSend($url, [], $injectHeaders, 'GET');

GET localhost/opentracing.php

PHP实现opentracing链路追踪相关推荐

  1. skywalking监控php,Skywalking PHP客户端编译安装 OpenTracing 链路追踪

    Skywalking PHP客户端 其实就是一个PHP扩展,按照官方说明来安装就行, 不要相信网上乱七八糟的说法,网上说需要安装report client我搞了半天没明白是啥, 问作者,作者回答不需要 ...

  2. 全链路追踪之OpenTracing

    链路追踪 现在的大多数互联网服务,基本都是用复杂,大规模分布式集群来实现,微服务化,这些服务模块分布在不同的机器,不同的数据中心,由不同团队,语言开发而成.因此,需要工具帮助理解,分析这些系统.定位问 ...

  3. 微服务,链路追踪,opentracing+jaeger(六)

    参考文档 opentracing详解:https://pjw.io/articles/2018/05/08/opentracing-explanations/ opentracing中文文档:http ...

  4. 监控、链路追踪、日志这三者有何区别?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:r6d.cn/mFJ6 1. 监控.链路追踪.日志 ...

  5. 原来10张图就可以搞懂分布式链路追踪系统原理

    分布式系统为什么需要链路追踪? 随着互联网业务快速扩展,软件架构也日益变得复杂,为了适应海量用户高并发请求,系统中越来越多的组件开始走向分布式化,如单体架构拆分为微服务.服务内缓存变为分布式缓存.服务 ...

  6. 快速搞懂监控、链路追踪、日志三者的区别

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | Xenojoshua 来源 | https:/ ...

  7. go 链路追踪_【go-micro实践】jaeger分布式链路追踪

    安装jaeger jaeger提供一个all in one 的docker镜像,可以快速搭建实验环境 docker run -d --name jaeger -e COLLECTOR_ZIPKIN_H ...

  8. ajax请求是宏任务还是微任务_微服务-如何解决链路追踪问题

    一.链路追踪 微服务架构是将单个应用程序被划分成各种小而连接的服务,每一个服务完成一个单一的业务功能,相互之间保持独立和解耦,每个服务都可以独立演进.相对于传统的单体服务,微服务具有隔离性.技术异构性 ...

  9. 分布式链路追踪框架的基本实现原理

    目录 分布式追踪 分布式系统 分布式追踪 分布式追踪有什么用呢 什么是分布式追踪 Dapper 分布式追踪系统的实现 跟踪树和 span Jaeger 和 OpenTracing OpenTracin ...

最新文章

  1. 利用partial快乐驱动开发
  2. 【ngx-ueditor】百度编辑器按下Shift键不触发contentChange事件
  3. php cookie加密 类,PHP cookie加密类
  4. AG3 hang after click membership search
  5. Express 入门之Router - worldtree_keeper的专栏 - CSDN博客
  6. 如何下载EP的各个版本?
  7. 用汇编的眼光看C++(之class构造、析构)
  8. CLR探索系列:深入追踪托管exe加载执行过程
  9. 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_11-MongoDb入门-安装Mongodb数据库...
  10. 数字城市厦门智慧防汛平台测试计划【软件测试与工程】
  11. 无U盘安装系统(到固态硬盘)教程
  12. 真相了!他说:码农和程序员的区别就在这!网友炸锅了
  13. python代码写龙卷风_python - 龙卷风服务器二进制可执行文件
  14. migration php,PHP日记——Lavarel常用语句之Migration篇
  15. vue项目中-上传图片头像并裁剪成任意大小的实现
  16. 各版本最新的Visual C++可再发行组件包(Redistributable Package)下载和合集
  17. 微信分享接口配置和调用
  18. k3显示远程服务器未打开,k3客户端远程服务器链接
  19. 微信小程序视频上传组件直接上传至阿里云OSS
  20. PayPal收款流程

热门文章

  1. 谷歌掐架甲骨文:揭秘Java侵权案始末
  2. ElasticSearch--Field的使用
  3. 马上就要十一大长假了!还没订好机票?用Python写了一个钉钉订低价票脚本!
  4. 视频加密中的“一机一码”是什么意思?
  5. android平板 跑分软件,安卓平板拿啥比?M1 iPad Pro跑分公布:差距实在太大
  6. [记录] 基于STC89C52RC的贪吃蛇三色游戏机设计(内含点阵驱动、数码管驱动详解)
  7. 腾讯优图实验室日常实习生招聘
  8. 震撼【超高细节地球】GIS相关引擎,速看。。。
  9. 六、路由(routing)
  10. 2015软件设计师考试(英语部分)