vantt / opentracing-php
PHP 的 OpenTracing API
Requires
- php: ^7.1 || ^8.0
Requires (Dev)
- phpstan/phpstan: ^0.9.3 || ~0.12
- phpunit/php-code-coverage: ^6.1||^9.1
- phpunit/phpunit: ^6.5.14 || ^7.0 || ^9.0
- squizlabs/php_codesniffer: 3.*
Replaces
- opentracing/opentracing: ~1.0.1
This package is auto-updated.
Last update: 2024-09-19 15:37:45 UTC
README
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\SpanContext
或OpenTracing\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\SpanContext
或OpenTracing\Span
的对象。references
是OpenTracing\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']
。此定义可以直接传递给curl
和file_get_contents
。 -
Tracer::FORMAT_BINARY
不假设数据格式,除了它是专有的并且每个tracer都可以按自己的方式处理它。
模拟实现
OpenTracing PHP附带了一个模拟实现,它有三个目的
- 帮助完善API。
- 作为参考实现。
- 增强无供应商单元测试,因为它允许开发人员检查跟踪对象以便对他们进行断言。
编码风格
OpenTracing PHP遵循PSR-2编码标准和PSR-4自动加载标准。
许可证
所有开源贡献均根据Apache-2.0许可证的条款。