PHP实现opentracing链路追踪
码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加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服务:
- 入口为 opentracing.php,调用了 opentracing1.php
- opentracing1.php 调用了2次 opentracing2.php 服务
- 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链路追踪相关推荐
- skywalking监控php,Skywalking PHP客户端编译安装 OpenTracing 链路追踪
Skywalking PHP客户端 其实就是一个PHP扩展,按照官方说明来安装就行, 不要相信网上乱七八糟的说法,网上说需要安装report client我搞了半天没明白是啥, 问作者,作者回答不需要 ...
- 全链路追踪之OpenTracing
链路追踪 现在的大多数互联网服务,基本都是用复杂,大规模分布式集群来实现,微服务化,这些服务模块分布在不同的机器,不同的数据中心,由不同团队,语言开发而成.因此,需要工具帮助理解,分析这些系统.定位问 ...
- 微服务,链路追踪,opentracing+jaeger(六)
参考文档 opentracing详解:https://pjw.io/articles/2018/05/08/opentracing-explanations/ opentracing中文文档:http ...
- 监控、链路追踪、日志这三者有何区别?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:r6d.cn/mFJ6 1. 监控.链路追踪.日志 ...
- 原来10张图就可以搞懂分布式链路追踪系统原理
分布式系统为什么需要链路追踪? 随着互联网业务快速扩展,软件架构也日益变得复杂,为了适应海量用户高并发请求,系统中越来越多的组件开始走向分布式化,如单体架构拆分为微服务.服务内缓存变为分布式缓存.服务 ...
- 快速搞懂监控、链路追踪、日志三者的区别
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | Xenojoshua 来源 | https:/ ...
- go 链路追踪_【go-micro实践】jaeger分布式链路追踪
安装jaeger jaeger提供一个all in one 的docker镜像,可以快速搭建实验环境 docker run -d --name jaeger -e COLLECTOR_ZIPKIN_H ...
- ajax请求是宏任务还是微任务_微服务-如何解决链路追踪问题
一.链路追踪 微服务架构是将单个应用程序被划分成各种小而连接的服务,每一个服务完成一个单一的业务功能,相互之间保持独立和解耦,每个服务都可以独立演进.相对于传统的单体服务,微服务具有隔离性.技术异构性 ...
- 分布式链路追踪框架的基本实现原理
目录 分布式追踪 分布式系统 分布式追踪 分布式追踪有什么用呢 什么是分布式追踪 Dapper 分布式追踪系统的实现 跟踪树和 span Jaeger 和 OpenTracing OpenTracin ...
最新文章
- 利用partial快乐驱动开发
- 【ngx-ueditor】百度编辑器按下Shift键不触发contentChange事件
- php cookie加密 类,PHP cookie加密类
- AG3 hang after click membership search
- Express 入门之Router - worldtree_keeper的专栏 - CSDN博客
- 如何下载EP的各个版本?
- 用汇编的眼光看C++(之class构造、析构)
- CLR探索系列:深入追踪托管exe加载执行过程
- 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_11-MongoDb入门-安装Mongodb数据库...
- 数字城市厦门智慧防汛平台测试计划【软件测试与工程】
- 无U盘安装系统(到固态硬盘)教程
- 真相了!他说:码农和程序员的区别就在这!网友炸锅了
- python代码写龙卷风_python - 龙卷风服务器二进制可执行文件
- migration php,PHP日记——Lavarel常用语句之Migration篇
- vue项目中-上传图片头像并裁剪成任意大小的实现
- 各版本最新的Visual C++可再发行组件包(Redistributable Package)下载和合集
- 微信分享接口配置和调用
- k3显示远程服务器未打开,k3客户端远程服务器链接
- 微信小程序视频上传组件直接上传至阿里云OSS
- PayPal收款流程
热门文章
- 谷歌掐架甲骨文:揭秘Java侵权案始末
- ElasticSearch--Field的使用
- 马上就要十一大长假了!还没订好机票?用Python写了一个钉钉订低价票脚本!
- 视频加密中的“一机一码”是什么意思?
- android平板 跑分软件,安卓平板拿啥比?M1 iPad Pro跑分公布:差距实在太大
- [记录] 基于STC89C52RC的贪吃蛇三色游戏机设计(内含点阵驱动、数码管驱动详解)
- 腾讯优图实验室日常实习生招聘
- 震撼【超高细节地球】GIS相关引擎,速看。。。
- 六、路由(routing)
- 2015软件设计师考试(英语部分)