vantt/opentracing-php

PHP 的 OpenTracing API

1.1.2 2021-02-19 07:48 UTC

This package is auto-updated.

Last update: 2024-09-19 15:37:45 UTC


README

Build Status OpenTracing Badge Total Downloads Minimum PHP Version License

PHP 的 OpenTracing API 库。

该库扩展了原始的 Tracer 接口,添加了新方法: buildSpan(string $operationName): SpanBuildInterface

必读

为了理解这个库,必须首先熟悉 OpenTracing 项目 以及 规范

安装

可以通过 Composer 安装 OpenTracing-PHP

composer require vantt/opentracing

用法

单例初始化

最简单的起点是设置全局追踪器。尽可能早地执行:

use OpenTracing\GlobalTracer;

$tracer = GlobalTracer::set(new MyTracerImplementation());

使用 SpanBuilder

此库扩展了原始 API 以添加新方法 buildSpan(operationName):SpanBuilderInterface。当使用此库时,您只需关注 $tracer 实例上的 buildSpan(operationName)Tracer::buildSpan(operationName)

使用 SpanBuilder,我们可以利用编辑器的功能,通过以下 API 进行自动代码补全:

  • asChildOf($parentContext)OpenTracing\SpanContextOpenTracing\Span 类型的对象。
  • withStartTimestamp(time()) 是表示任意精度的时间戳的浮点数、整数或 \DateTime
  • withTag(key,val) 是一个具有字符串键和标量值的数组,表示 OpenTracing 标签。
  • ignoreActiveSpan(bool)
  • finishSpanOnClose() 是一个布尔值,用于确定在作用域关闭时是否应该完成 span。
  • addReference()

以下是演示一些重要用例的代码片段

$span = $tracer->buildSpan('my_span')
               ->asChildOf($parentContext)
               ->withTag('foo', 'bar')               
               ->withStartTimestamp(time())
               ->start();

$scope = $tracer->buildSpan('my_span')
                ->asChildOf($parentContext)
                ->withTag('foo', 'bar')               
                ->withStartTimestamp(time())
                ->startActive();

根据现有请求创建 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()->buildSpan('my_operation_span_name')
                               ->start();
    ...
    
    // add some logs to the span
    $span->log([
        'event' => 'soft error',
        'type' => 'cache timeout',
        'waiter.millis' => 1500,
    ]);

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

通过创建 "root span" 开始新的跟踪

始终可以创建一个没有父级或其他因果引用的 "root" Span

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

活动 Span 和作用域管理器

对于大多数用例,建议您使用 Tracer::startActiveSpan 函数创建新的 span。

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

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

当使用 Tracer::startActiveSpan 函数时,底层追踪器使用一个称为作用域管理器的抽象来跟踪当前活动 span。

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

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

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

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

手动指定父级创建子 span

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

$child = $tracer->buildSpan('child_operation')
                ->asChildOf($parent)
                ->start();
...

$child->finish();

...

$parent->finish();

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

每个新的 span 都会将活动 span 作为父级,并占据其位置。

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

...

/*
 * 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()->buildSpan('my_second_span')->startActive();

...

$child->close();

...

$parent->close();

序列化到线上

use GuzzleHttp\Client;
use OpenTracing\Formats;

...

$tracer = GlobalTracer::get();

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

try {
    $span = $tracer->buildSpan('my_span')->asChildOf($spanContext)->start();

    $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->buildSpan('my_span')->asChildOf($spanContext)->startActive();

清除Spans

PHP作为一个请求作用域的语言,没有简单的方法在不阻塞主请求线程/进程的情况下将收集到的spans数据传递给后台进程。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发送到后端。对于这些tracer,flush调用可以实现为NO-OP。

使用StartSpanOptions

此库仍然与StartSpanOption兼容。

传递选项可以使用数组或SpanOptions包装对象。以下键是有效的

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

传播格式

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

  • Tracer::FORMAT_TEXT_MAP应将span上下文表示为一个键值映射。没有假设上下文来自哪里以及发送到哪里。

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

  • Tracer::FORMAT_BINARY不假设数据格式,除了它是专有的并且每个tracer都可以按自己的方式处理它。

模拟实现

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

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

编码风格

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

许可证

所有开源贡献均根据Apache-2.0许可证的条款。