mix-plus/opentracing

PHP的OpenTracing API

3.0.0 2022-04-20 03:11 UTC

README

Build OpenTracing Badge Total Downloads Minimum PHP Version License Join the chat at https://gitter.im/opentracing/opentracing-php

PHP库,用于OpenTracing的API。

必读

为了理解这个库,首先需要熟悉OpenTracing项目规范

安装

可以通过Composer安装OpenTracing-PHP

composer require opentracing/opentracing

用法

在使用此库时,实际上只需要关注几个关键抽象:Tracer::startActiveSpanTracer::startSpan方法、Span接口、Scope接口以及在引导时绑定Tracer。以下是一些代码片段,展示了重要的使用案例

单例初始化

最简单的起点是设置全局tracer。尽可能早地做

use OpenTracing\GlobalTracer;

GlobalTracer::set(new MyTracerImplementation());

根据现有的请求创建Span

要启动一个新的Span,可以使用startSpan方法。

use OpenTracing\Formats;
use OpenTracing\GlobalTracer;

...

// extract the span context
$spanContext = GlobalTracer::get()->extract(
    Formats\HTTP_HEADERS,
    getallheaders()
);

function doSomething() {
    ...

    // start a new span called 'my_span' and make it a child of the $spanContext
    $span = GlobalTracer::get()->startSpan('my_span', ['child_of' => $spanContext]);

    ...
    
    // add some logs to the span
    $span->log([
        'event' => 'soft error',
        'type' => 'cache timeout',
        'waiter.millis' => 1500,
    ])

    // finish the the span
    $span->finish();
}

通过创建“根span”来启动新的跟踪

总是可以创建一个没有父span或其他因果引用的“根”Span

$span = $tracer->startSpan('my_first_span');
...
$span->finish();

活动Span和范围管理器

对于大多数使用场景,建议使用Tracer::startActiveSpan函数来创建新的span。

以下是在PHP代码中线性、两层深的span树使用活动span的示例

// At dispatcher level
$scope = $tracer->startActiveSpan('request');
...
$scope->close();
// At controller level
$scope = $tracer->startActiveSpan('controller');
...
$scope->close();
// At RPC calls level
$scope = $tracer->startActiveSpan('http');
file_get_contents('https://php.ac.cn');
$scope->close();

当使用Tracer::startActiveSpan函数时,底层的tracer使用一个名为范围管理器的抽象来跟踪当前活动的span。

启动活动span将始终使用当前活动的span作为父span。如果没有可用的父span,则新创建的span被认为是跟踪的根span。

除非您正在使用跟踪多个span的异步代码,例如在使用cURL Multi Exec或MySQLi Polling时,否则建议您在应用程序的每个地方都使用Tracer::startActiveSpan

当您调用$scope->close()时,当前活动span会自动完成,如前面的示例所示。

如果您不希望在调用$scope->close()时自动关闭span,则必须在startActiveSpan$options参数中指定'finish_span_on_close'=> false,

手动指定父span创建子span

$parent = GlobalTracer::get()->startSpan('parent');

$child = GlobalTracer::get()->startSpan('child', [
    'child_of' => $parent
]);

...

$child->finish();

...

$parent->finish();

使用自动活动span管理创建子span

每个新的span都将使用活动span作为父span,并将其放在适当的位置。

$parent = GlobalTracer::get()->startActiveSpan('parent');

...

/*
 * Since the parent span has been created by using startActiveSpan we don't need
 * to pass a reference for this child span
 */
$child = GlobalTracer::get()->startActiveSpan('my_second_span');

...

$child->close();

...

$parent->close();

序列化到传输线

use GuzzleHttp\Client;
use OpenTracing\Formats;

...

$tracer = GlobalTracer::get();

$spanContext = $tracer->extract(
    Formats\HTTP_HEADERS,
    getallheaders()
);

try {
    $span = $tracer->startSpan('my_span', ['child_of' => $spanContext]);

    $client = new Client;

    $headers = [];

    $tracer->inject(
        $span->getContext(),
        Formats\HTTP_HEADERS,
        $headers
    );

    $request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice', $headers);
    $client->send($request);
    ...

} catch (\Exception $e) {
    ...
}
...

从传输线反序列化

当使用http头进行上下文传播时,您可以使用Request$_SERVER变量。

use OpenTracing\GlobalTracer;
use OpenTracing\Formats;

$tracer = GlobalTracer::get();
$spanContext = $tracer->extract(Formats\HTTP_HEADERS, getallheaders());
$tracer->startSpan('my_span', [
    'child_of' => $spanContext,
]);

清除Span

PHP作为一种请求范围的语言,没有简单的方法在不阻塞主请求线程/进程的情况下将收集到的span数据传递给后台进程。OpenTracing API对此没有假设,但对于PHP来说,这可能会对tracer实现造成问题。这就是为什么PHP API包含一个flush方法,允许触发将span发送到进程外。

use OpenTracing\GlobalTracer;

$application->run();

register_shutdown_function(function() {
    /* Flush the tracer to the backend */
    $tracer = GlobalTracer::get();
    $tracer->flush();
});

这是可选的,tracer可以决定立即将已完成的span发送到后端。flush调用可以对这些tracer实现为NO-OP。

使用StartSpanOptions

传递选项可以通过数组或SpanOptions包装器对象实现。以下键是有效的

  • start_time是一个浮点数、整数或\DateTime,表示具有任意精度的时间戳。
  • child_of 是类型为 OpenTracing\SpanContextOpenTracing\Span 的对象。
  • references 是一个 OpenTracing\Reference 数组。
  • tags 是一个带有字符串键和标量值的数组,代表 OpenTracing 标签。
  • finish_span_on_close 是一个布尔值,用于确定当作用域关闭时是否应该完成跨度。
$span = $tracer->startActiveSpan('my_span', [
    'child_of' => $spanContext,
    'tags' => ['foo' => 'bar'],
    'start_time' => time(),
]);

传播格式

传播格式应在所有跟踪器中一致实现。如果您想实现自己的格式,则不要重用现有常量。如果请求的格式不被跟踪器处理,跟踪器将抛出异常。

  • Tracer::FORMAT_TEXT_MAP 应将跨度上下文表示为键值映射。没有关于上下文来源和发送到哪里的语义假设。

  • Tracer::FORMAT_HTTP_HEADERS 应将跨度上下文表示为数组列表中的 HTTP 头行。对于两个上下文详细信息 "Span-Id" 和 "Trace-Id",结果将是 ['Span-Id: abc123', 'Trace-Id: def456']。这个定义可以直接传递给 curlfile_get_contents

  • Tracer::FORMAT_BINARY 对数据格式没有假设,除了它属于专有格式且每个跟踪器可以按自己的方式处理。

模拟实现

OpenTracing PHP 附带一个模拟实现,它有三个目的

  1. 帮助完善 API。
  2. 作为参考实现。
  3. 增强了无供应商单元测试,因为它允许开发者检查跟踪对象以便对他们进行断言。

编码风格

OpenTracing PHP 遵循 PSR-2 编码标准和 PSR-4 自动加载标准。

许可证

所有开源贡献均受 Apache-2.0 许可证 的约束。