开发环境:

php >= 5.6

linux环境 必须安装thrift

omposer require opentracing/opentracing  1.0.0-beta5
composer require jukylin/jaeger-php v2.1.3

 下面展示一个进程内和跨进程的访问

PHP实现opentracing jaeger链路追踪_项目代码




http代码中分别请求了crm.ichunt.com,baidu.com;在访问了baidu.com嵌套了子span访问ichunt.com;接下来访问http2.php


http2代码中 访问了ichunt.com和crm.ichunt.com


PHP实现opentracing jaeger链路追踪_项目代码_02PHP实现opentracing jaeger链路追踪_php_03

<?php
/*
* Copyright (c) 2019, The Jaeger Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

require_once './vendor/autoload.php';

use Jaeger\Config;
use GuzzleHttp\Client;
use OpenTracing\Formats;
use OpenTracing\Reference;

unset($_SERVER['argv']);

set_time_limit(0);
//init server span start
$config = Config::getInstance();
$config->gen128bit();
$config::$propagator = Jaeger\Constants\PROPAGATOR_JAEGER;
$tracer = $config->initTracer('example-php', '192.168.1.234:6831');
$injectTarget = [];
$spanContext = $tracer->extract(Formats\TEXT_MAP, $_SERVER);
echo sprintf("parent-spanContext %s <br>",print_r($spanContext,true));
if(!$spanContext){
$serverSpan = $tracer->startSpan('example HTTP');
}else{
$serverSpan = $tracer->startSpan('example HTTP', ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $spanContext),
Reference::create(Reference::CHILD_OF, $spanContext)
]]);
}
$serverSpan->addBaggageItem("version", "1.8.9");
$serverSpan->setTag("serverSpan-key","serverSpan-value");
$tracer->inject($serverSpan->getContext(), Formats\TEXT_MAP, $_SERVER);
//init server span end
$clientTracer = $config->initTracer('HTTP');






//client span1 start
$injectTarget1 = [];
$spanContext1 = $clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
echo sprintf("spanContext1 %s <br>",print_r($spanContext1,true));
$clientSpan1 = $clientTracer->startSpan('request1', ['child_of' => $spanContext1]);
$clientTracer->inject($clientSpan1->spanContext, Formats\TEXT_MAP, $injectTarget1);

$method = 'GET';
$url = 'http://baidu.com/';
$client = new Client();
$res = $client->request($method, $url,['headers' => $injectTarget1]);

$clientSpan1->setTag('http.status_code', 200);
$clientSpan1->setTag('http.method', 'GET');
$clientSpan1->setTag('http.url', $url);
$clientSpan1->addBaggageItem("event","event-HTTP1-value");
$clientSpan1->log(['message' => "HTTP1 ". $method .' '. $url .' end !']);
$clientSpan1->finish();
//client span1 end

//--------------------------------------------------------------------------------------------

//client span2 start
$injectTarget2 = [];
$spanContext2 = $clientTracer->extract(Formats\TEXT_MAP,$_SERVER);
echo sprintf("spanContext2 %s <br>",print_r($spanContext2,true));
$clientSpan2 = $clientTracer->startSpan('request2',['references' => [
Reference::create(Reference::FOLLOWS_FROM, $clientSpan1->spanContext),
Reference::create(Reference::CHILD_OF, $spanContext1)
]]);
$clientTracer->inject($clientSpan2->spanContext, Formats\TEXT_MAP, $injectTarget2);
$method = 'GET';
//$url = 'http://192.168.1.169:8088/http2.php';
$url = 'http://ichunt.com/';
$client = new Client();
$res = $client->request($method, $url, ['headers' => $injectTarget2]);
$clientSpan2->setTag('http.status_code', 200);
$clientSpan2->setTag('http.method', 'GET');
$clientSpan2->setTag('http.url', $url);
$clientSpan2->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan2->finish();
////client span2 end


//--------------------------------------------------------------------------------------------



//client span3 start
$injectTarget3 = [];
$spanContext3 = $clientTracer->extract(Formats\TEXT_MAP,$_SERVER);
echo sprintf("spanContext3 %s <br>",print_r($spanContext3,true));
$clientSpan3 = $clientTracer->startSpan('request3',
['references' => [
Reference::create(Reference::FOLLOWS_FROM, $spanContext3),
Reference::create(Reference::CHILD_OF, $spanContext3)
]]);
$clientTracer->inject($clientSpan3->spanContext, Formats\TEXT_MAP, $injectTarget3);
$method = 'GET';
$url = 'http://crm.ichunt.net/';
$client = new Client();
$res = $client->request($method, $url, ['headers' => $injectTarget3]);

$clientSpan3->setTag('http.status_code', 200);
$clientSpan3->setTag('http.method', 'GET');
$clientSpan3->setTag('http.url', $url);

$clientSpan3->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan3->finish();
////client span3 end


//--------------------------------------------------------------------------------------------

//client span2 start
$injectTarget4 = [];
$spanContext4 = $clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
echo sprintf("spanContext4 %s <br>",print_r($spanContext4,true));
$clientSpan4 = $clientTracer->startSpan('request4',
['references' => [
Reference::create(Reference::FOLLOWS_FROM, $spanContext4),
Reference::create(Reference::CHILD_OF, $spanContext4)
]]);

$clientTracer->inject($clientSpan4->spanContext, Formats\TEXT_MAP, $injectTarget4);

$method = 'GET';
$url = 'http://192.168.1.169/http2.php';
$client = new Client();
$res = $client->request($method, $url, ['headers' => $injectTarget4]);

$clientSpan4->setTag('http.status_code', 200);
$clientSpan4->setTag('http.method', 'GET');
$clientSpan4->setTag('http.url', $url);

$clientSpan4->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan4->finish();
//client span2 end













////server span end
$serverSpan->finish();
//trace flush
$config->flush();

echo "success\r\n";

http.php


PHP实现opentracing jaeger链路追踪_项目代码_02PHP实现opentracing jaeger链路追踪_php_03

<?php
/*
* Copyright (c) 2019, The Jaeger Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

require_once './vendor/autoload.php';

use Jaeger\Config;
use GuzzleHttp\Client;
use OpenTracing\Formats;
use OpenTracing\Reference;

unset($_SERVER['argv']);


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;
}

$config = Config::getInstance();
$config->gen128bit();
$config::$propagator = Jaeger\Constants\PROPAGATOR_JAEGER;
$tracer = $config->initTracer('http2-php', '192.168.1.234:6831');
$spanContext = $tracer->extract(Formats\TEXT_MAP, getAllHeaders());
if(!$spanContext){
$serverSpan = $tracer->startSpan('Istio2');
}else{
$serverSpan = $tracer->startSpan('Istio2', ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $spanContext),
Reference::create(Reference::CHILD_OF, $spanContext)
]]);
}
$serverSpan->setTag("parent","parent-span");
$serverSpan->log(["parent"=>"parent-log"]);
$tracer->inject($serverSpan->getContext(), Formats\TEXT_MAP, $_SERVER);

$clientTracer = $config->initTracer('HTTP');


//-------------------------
$injectTarget2 = [];
$spanContext = $clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
print_r($spanContext);
if(!$spanContext){
$clientSpan2 = $clientTracer->startSpan('request2');
}else{
$clientSpan2 = $clientTracer->startSpan('request2', ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $serverSpan->spanContext),
Reference::create(Reference::CHILD_OF, $spanContext)
]]);
}

$clientTracer->inject($clientSpan2->spanContext, Formats\TEXT_MAP, $injectTarget2);
$method = 'GET';
$url = 'http://ichunt.com/';
$client = new Client();
$res = $client->request($method, $url, ['headers' => $injectTarget2]);
$clientSpan2->setTag('http.status_code', 200);
$clientSpan2->setTag('http.method', 'GET');
$clientSpan2->setTag('http.url', $url);
$clientSpan2->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan2->finish();
//---------------------------------------


//client span3 start
$injectTarget3 = [];
$spanContext3 = $clientTracer->extract(Formats\TEXT_MAP,$_SERVER);
print_r($spanContext3);
if(!$spanContext3){
$clientSpan3 = $clientTracer->startSpan('request3');
}else{
$clientSpan3 = $clientTracer->startSpan('request3',
['references' => [
Reference::create(Reference::FOLLOWS_FROM, $spanContext3),
Reference::create(Reference::CHILD_OF, $spanContext3)
]]);
}
$clientTracer->inject($clientSpan3->spanContext, Formats\TEXT_MAP, $injectTarget3);
$method = 'GET';
$url = 'http://crm.ichunt.net/';
$client = new Client();
$res = $client->request($method, $url, ['headers' => $injectTarget3]);

$clientSpan3->setTag('http.status_code', 200);
$clientSpan3->setTag('http.method', 'GET');
$clientSpan3->setTag('http.url', $url);

$clientSpan3->log(['message' => "HTTP2 ". $method .' '. $url .' end !']);
$clientSpan3->finish();
////client span3 end














////server span end
$serverSpan->finish();
//trace flush
$config->flush();

echo "success\r\n";

http2.php


PHP实现opentracing jaeger链路追踪_.net_06


 PHP实现opentracing jaeger链路追踪_php_07


对上面代码进行封装:


JaegerInject.php
<?phpnamespace Common\Service;

use Jaeger\Config as Jconfing;
use OpenTracing\Formats;
use OpenTracing\Reference;


class JaegerInject
{

protected $dsn = '192.168.1.234:6831';

protected $serviceName;
protected $spanList = [];
protected $client;
protected $tracer;
protected $clientTracer;

public function __construct($serviceName = 'opentarcing-php',$parentSpanName="")
{
$this->serviceName = $serviceName;
unset($_SERVER['argv']);
$this->client = Jconfing::getInstance();
Jconfing::$propagator = \Jaeger\Constants\PROPAGATOR_JAEGER;
$this->client->gen128bit();
$this->tracer = $this->client->initTracer($this->serviceName, $this->dsn);
$parentContext = $this->tracer->extract(Formats\TEXT_MAP, $this->getAllHeaders());
if (!$parentContext) {
$serverSpan = $this->tracer->startSpan($parentSpanName);
} else {
$serverSpan = $this->tracer->startSpan($parentSpanName, ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $parentContext),
Reference::create(Reference::CHILD_OF, $parentContext)
]]);
}
$serverSpan->setTag("parent","123");
$this->tracer->inject($serverSpan->getContext(),Formats\TEXT_MAP, $_SERVER);
$this->clientTracer = $this->client->initTracer('HTTP');
$this->spanList[$parentSpanName]=[
"current_span"=>$serverSpan,
"parent_context"=>$parentContext
];
}


public function getSpanName($spanName){
return isset($this->spanList[$spanName]) ? $this->spanList[$spanName]["current_span"] : "";
}

public function setTag($spanName,$key="",$value=""){
if(!isset($this->spanList[$spanName])){
return ;
}
$info = $this->spanList[$spanName];
$span = $info['current_span'];
$span->setTag($key,$value);
}


public function log($spanName,$key="",$value=""){
if(!isset($this->spanList[$spanName])){
return ;
}
$info = $this->spanList[$spanName];
$span = $info['current_span'];
$span->log([$key=>$value]);
}


public function start($spanName,$parentSpan="")
{
$spanContext = $this->clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
$clientrSpan = null;
$parentSpanIsObj = $parentSpan && gettype($parentSpan) == "object";
if (!$spanContext) {
$clientrSpan = $this->tracer->startSpan($spanName);
} else {
$clientrSpan = $this->tracer->startSpan($spanName, ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $parentSpanIsObj ? $parentSpan->spanContext :$spanContext),
Reference::create(Reference::CHILD_OF, $spanContext)
]]);
}

$this->spanList[$spanName]=[
"current_span"=>$clientrSpan,
"parent_context"=>$parentSpanIsObj ? $parentSpan->spanContext :$spanContext,
];
}


public function inject($spanName)
{
$info = $this->spanList[$spanName];
$span = $info['current_span'];
$injectHeaders = [];
$this->clientTracer->inject($span->getContext(), Formats\TEXT_MAP, $injectHeaders);
return $injectHeaders;
}


public function finish( $spanName, array $spanList = [])
{
$info = $this->spanList[$spanName];

$span = $info['current_span'];
$parentContext = $info['parent_context'];

$span->setTag('parentSpan', $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();
}

}



public function opentarcing_one(){
$jaeger = new \Common\Service\JaegerInject("opentarcing-php","opentarcing_one");
$jaeger->setTag("opentarcing_one","事件","创建订单");
$jaeger->log("opentarcing_one","请求参数",json_encode(cookie()));


$spanName = "order-admin";
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://crm.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);

$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);


$spanName = "ichunt-api";
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://order.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);



//--------------crm.net-----下包含子span---crm.child.net------------------------------
$spanName = "crm.net";
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://label.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);


$spanName = "crm.child.net";
$parentSpanName = $jaeger->getSpanName("crm.net");
$jaeger->start($spanName,$parentSpanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://crm.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);

//----------------crm.net-----下包含子span---crm.child.net-------------------------------



$spanName = "跨进程访问http2.php";
$jaeger->start($spanName);

$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://api.liexin.com/order/test/opentarcing_two';
$jar = new \GuzzleHttp\Cookie\CookieJar();
$cookieJar = $jar->fromArray(cookie(), "liexin.com");
$res = $client->request($method, $url, ['headers' => $injectHeaders,"cookies"=>$cookieJar]);
// dump(cookie());
// $res = post_curl($url,[],$injectHeaders);

$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);


}

public function opentarcing_two()
{
$jaeger = new \Common\Service\JaegerInject("opentarcing-php","opentarcing_two");

$spanName = "crm.net";
$jaeger->start($spanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://label.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);


$spanName = "crm.child.net";
$parentSpanName = $jaeger->getSpanName("crm.net");
$jaeger->start($spanName,$parentSpanName);
$injectHeaders = $jaeger->inject($spanName);
$client = new \GuzzleHttp\Client;
$method = 'GET';
$url = 'http://crm.ichunt.net/';
$res = $client->request($method, $url, ['headers' => $injectHeaders]);
$jaeger->finish($spanName, ['time' => date('Y-m-d H:i:s')]);

}




 PHP实现opentracing jaeger链路追踪_项目代码_08


生产场景使用后优化代码

上述代码在生产实践中发现每次实例化一个JaegerInject对象就会创建一个udp请求;

优化目的:一次请求创建一次udp请求

建议:使用中尽量能使用同一个JaegerInject对象


checkPhpUname方法 为了防止windows电脑上无法运行thirft
/*
* 判断运行环境是否是linux
*/
function checkPhpUname(){
$os_name = PHP_OS;
if(strpos($os_name,"Linux")!==false){
return true;
}else{
return false;
}
}

PHP实现opentracing jaeger链路追踪_项目代码_02PHP实现opentracing jaeger链路追踪_php_03

<?php
namespace Common\Service;

use Jaeger\Config as Jconfing;
use OpenTracing\Formats;
use OpenTracing\Reference;


class JaegerInject
{

protected $dsn = '192.168.1.234:6831';

protected $serviceName;
public static $spanList = [];
protected $client;
protected $tracer;
protected $clientTracer;
protected $uname;//开发环境 window mac linux
public static $parentSpanName = null;
public static $instance = null;



private function __construct(){

}


private function __clone(){

}

public static function getInstance()
{
if(! (self::$instance instanceof self) )
{
self::$instance = new self();
}
return self::$instance;
}


protected function getClientIp()
{
$ip = '0.0.0.0';
if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
}
if (getenv('HTTP_X_REAL_IP')) {
$ip = getenv('HTTP_X_REAL_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
$ips = explode(',', $ip);
$ip = $ips[0];
} elseif (getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
}

return $ip;
}


public function getSpanName($spanName){
if(!$this->uname){
return "";
}

return isset(static::$spanList[$spanName]) ? static::$spanList[$spanName]["current_span"] : "";
}


public function setTag($spanName,$key="",$value=""){
if(!$this->uname){
return "";
}
if(!isset(static::$spanList[$spanName])){
return ;
}
$info = static::$spanList[$spanName];
$span = $info['current_span'];
$span->setTag($key,$value);
}


/*
* 记录链路追踪日志
*/
public function log($spanName,$key="",$value=""){
if(!$this->uname){
return "";
}
if(!isset(static::$spanList[$spanName])){
return ;
}
$info = static::$spanList[$spanName];
$span = $info['current_span'];
if($key && $value){
$span->log([$key=>$value]);
}else if($key && !$value){
$span->log(["message"=>$key]);
}
}


/*
* 創建父span
*/
public function init($parentSpanName=""){

$this->serviceName = C("OPENTRACING_JAEGER_SERVERNAME");
$this->client = Jconfing::getInstance();
Jconfing::$propagator = \Jaeger\Constants\PROPAGATOR_JAEGER;
$this->client->gen128bit();
$this->tracer = $this->client->initTracer($this->serviceName, C("OPENTRACING_JAEGER_DNS"));

if(!static::$parentSpanName && !$parentSpanName){
static::$parentSpanName = "未知的spanName";
if(isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI']){
$requestUrl = explode("?",$_SERVER['REQUEST_URI']);
static::$parentSpanName = !empty($requestUrl) ? $requestUrl[0] : static::$parentSpanName;
}

}

if($parentSpanName && !static::$parentSpanName){
static::$parentSpanName = $parentSpanName;
}

if(!isset(static::$spanList[static::$parentSpanName])) {
if(!checkPhpUname()){
$this->uname = false;
return ;
}else{
$this->uname = true;
}
$this->startPrentSpan();
}
}


public function simpleInit($parentSpanName="",$spanName=""){
$this->init($parentSpanName);
$this->start($spanName);
$injectHeaders = $this->inject($spanName);
return $injectHeaders;
}

public function simpleInject($spanName,$preSpanName=""){
if($preSpanName){
$preSpanName = $this->getSpanName($preSpanName);
}
$this->start($spanName,$preSpanName);
$injectHeaders = $this->inject($spanName);
return $injectHeaders;
}

protected function startPrentSpan(){
$parentSpanName = static::$parentSpanName;
$parentContext = $this->tracer->extract(Formats\TEXT_MAP, $this->getAllHeaders());
// dump($parentContext);
if (!$parentContext) {
$serverSpan = $this->tracer->startSpan($parentSpanName);
} else {
$serverSpan = $this->tracer->startSpan($parentSpanName, ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $parentContext),
Reference::create(Reference::CHILD_OF, $parentContext)
]]);
}
$serverSpan->setTag("http_host",$this->getClientIp());
$serverSpan->setTag("time",date("Y-m-d H:i:s"));
if(isset($_SERVER['REQUEST_SCHEME'])){
$serverSpan->setTag("request_scheme",$_SERVER['REQUEST_SCHEME']);
}
if(isset($_SERVER['REQUEST_URI'])){
$serverSpan->setTag("request_uri",$_SERVER['REQUEST_URI']);
}

if(!empty($_REQUEST)){
$serverSpan->log(["request_params"=>json_encode($_REQUEST)]);
}

$this->tracer->inject($serverSpan->getContext(),Formats\TEXT_MAP, $_SERVER);
$this->clientTracer = $this->client->initTracer('HTTP');
static::$spanList[$parentSpanName]=[
"current_span"=>$serverSpan,
"parent_context"=>$parentContext
];
}


/*
* 創建子span
*/
public function start($spanName,$parentSpan="")
{
if(!$this->uname){
return ;
}

$spanContext = $this->clientTracer->extract(Formats\TEXT_MAP, $_SERVER);
$clientrSpan = null;
$parentSpanIsObj = $parentSpan && gettype($parentSpan) == "object";
if (!$spanContext) {
$clientrSpan = $this->tracer->startSpan($spanName);
} else {
$clientrSpan = $this->tracer->startSpan($spanName, ['references' => [
Reference::create(Reference::FOLLOWS_FROM, $parentSpanIsObj ? $parentSpan->spanContext :$spanContext),
Reference::create(Reference::CHILD_OF, $spanContext)
]]);
}

static::$spanList[$spanName]=[
"current_span"=>$clientrSpan,
"parent_context"=>$parentSpanIsObj ? $parentSpan->spanContext :$spanContext,
];
}


public function inject($spanName)
{
if(!$this->uname){
return [];
}
if(!isset(static::$spanList[$spanName])){
return [];
}
$info = static::$spanList[$spanName];
$span = $info['current_span'];
$injectHeaders = [];
$this->clientTracer->inject($span->getContext(), Formats\TEXT_MAP, $injectHeaders);
return $injectHeaders;
}


public function finish( $spanName, array $spanList = [])
{
if(!$this->uname){
return;
}
if(!isset(static::$spanList[$spanName])){
return;
}
$info = static::$spanList[$spanName];

$span = $info['current_span'];
$parentContext = $info['parent_context'];

$span->setTag('parentSpan', $parentContext ? $parentContext->spanIdToString() : '');
$span->setTag("time",date("Y-m-d H:i:s"));
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($_SERVER["UBER-TRACE-ID"])){
$headers["UBER-TRACE-ID"] = $_SERVER["UBER-TRACE-ID"];
}

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()
{
if(!$this->uname){
return ;
}
$this->client->flush();
}

}

JaegerInject

正常情况下在项目基类里面实例化一个对象 ,全局调用即可

$this->opentracingJager = \Common\Service\JaegerInject::getInstance();

接下来在支付会调用使用:

//顶级span
$this->opentracingJager->init("pay");
//....项目代码.........
//添加tag标签
$this->opentracingJager->setTag("pay","action","returnUrl");
$this->opentracingJager->setTag("pay","remark",sprintf("--支付同步回调--"));
//....项目代码.........
//添加日志
$this->opentracingJager->log("pay",sprintf("支付、充值同步回调异常:%s",json_encode($res)));
//....项目代码.........


//添加兄弟层span
$this->opentracingJager->simpleInject("payment");
$this->opentracingJager->log("payment","Pay->response()返回的数据",sprintf("%s",json_encode($arr)));
//....项目代码.........
$this->opentracingJager->finish("payment");




//....项目代码.........
$this->opentracingJager->finish("pay");





//添加一个子span
//上述代码中如果需要在payment span下面添加子节点
$this->opentracingJager->init("xxx");
//$jaeger->simpleInject("xxx","父span名字");
$jaeger->simpleInject("xxx","payment");
//添加tag标签
$this->opentracingJager->setTag("xxx","action","123");
$this->opentracingJager->setTag("xxx","remark",sprintf("--支付同步回调--"));
//添加日志
$this->opentracingJager->log("xxx",sprintf("支付、充值同步回调异常:%s",json_encode($res)));

//....项目代码.........
$this->opentracingJager->finish("xxx");