PHP实现opentracing jaeger链路追踪

开发环境:

php >= 5.6

linux环境 必须安装thrift

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

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

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

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

<?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 JaegerConfig;
use GuzzleHttpClient;
use OpenTracingFormats;
use OpenTracingReference;

unset($_SERVER['argv']);

set_time_limit(0);
//init server span start
$config = Config::getInstance();
$config->gen128bit();
$config::$propagator = JaegerConstantsPROPAGATOR_JAEGER;
$tracer = $config->initTracer('example-php', '192.168.1.234:6831');
$injectTarget = [];
$spanContext = $tracer->extract(FormatsTEXT_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(), FormatsTEXT_MAP, $_SERVER);
//init server span end
$clientTracer = $config->initTracer('HTTP');






//client span1 start
$injectTarget1 = [];
$spanContext1 = $clientTracer->extract(FormatsTEXT_MAP, $_SERVER);
echo sprintf("spanContext1 %s <br>",print_r($spanContext1,true));
$clientSpan1 = $clientTracer->startSpan('request1', ['child_of' => $spanContext1]);
$clientTracer->inject($clientSpan1->spanContext, FormatsTEXT_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(FormatsTEXT_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, FormatsTEXT_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(FormatsTEXT_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, FormatsTEXT_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(FormatsTEXT_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, FormatsTEXT_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
";
http.php
<?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 JaegerConfig;
use GuzzleHttpClient;
use OpenTracingFormats;
use OpenTracingReference;

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 = JaegerConstantsPROPAGATOR_JAEGER;
$tracer = $config->initTracer('http2-php', '192.168.1.234:6831');
$spanContext = $tracer->extract(FormatsTEXT_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(), FormatsTEXT_MAP, $_SERVER);

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


//-------------------------
$injectTarget2 = [];
$spanContext = $clientTracer->extract(FormatsTEXT_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, FormatsTEXT_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(FormatsTEXT_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, FormatsTEXT_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
";
http2.php

 

对上面代码进行封装:

JaegerInject.php
<?phpnamespace CommonService;

use JaegerConfig as Jconfing;
use OpenTracingFormats;
use OpenTracingReference;


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 = JaegerConstantsPROPAGATOR_JAEGER;
        $this->client->gen128bit();
        $this->tracer = $this->client->initTracer($this->serviceName, $this->dsn);
        $parentContext = $this->tracer->extract(FormatsTEXT_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(),FormatsTEXT_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(FormatsTEXT_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(), FormatsTEXT_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 CommonServiceJaegerInject("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 GuzzleHttpClient;
        $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 GuzzleHttpClient;
        $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 GuzzleHttpClient;
        $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 GuzzleHttpClient;
        $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 GuzzleHttpClient;
        $method = 'GET';
        $url = 'http://api.liexin.com/order/test/opentarcing_two';
        $jar = new GuzzleHttpCookieCookieJar();
        $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 CommonServiceJaegerInject("opentarcing-php","opentarcing_two");

        $spanName = "crm.net";
        $jaeger->start($spanName);
        $injectHeaders = $jaeger->inject($spanName);
        $client =  new GuzzleHttpClient;
        $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 GuzzleHttpClient;
        $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')]);

    }

 

生产场景使用后优化代码

上述代码在生产实践中发现每次实例化一个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
namespace CommonService;

use JaegerConfig as Jconfing;
use OpenTracingFormats;
use OpenTracingReference;


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 = JaegerConstantsPROPAGATOR_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(FormatsTEXT_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(),FormatsTEXT_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(FormatsTEXT_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(), FormatsTEXT_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 = CommonServiceJaegerInject::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");
原文地址:https://www.cnblogs.com/sunlong88/p/15103072.html