nightio / zipkin
PHP 的 Zipkin 仪表化工具
Requires
- php: ^7.1||^8.0
- ext-curl: *
- psr/http-message: ~1.0
- psr/log: ^1.0
Requires (Dev)
- guzzlehttp/psr7: ^1.6
- jcchavezs/httptest: ~0.2
- middlewares/fast-route: ^1.2.1
- middlewares/request-handler: ^1.4.0
- phpstan/phpstan: ~0.12.28
- phpunit/phpunit: ~7.5.20
- psr/http-client: ^1.0
- psr/http-server-middleware: ^1.0
- squizlabs/php_codesniffer: 3.*
Suggests
- psr/http-client: Allows to instrument HTTP clients following PSR18.
- psr/http-server-middleware: Allows to instrument HTTP servers via middlewares following PSR15.
Replaces
- v2.x-dev
- dev-master / 2.0.x-dev
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 2.0.0-beta1
- v1.x-dev
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.1
- 1.1.0
- 1.0.2
- 1.0.1
- 1.0.0
- 1.0.0-beta7
- 1.0.0-beta6
- 1.0.0-beta5
- 1.0.0-beta4
- 1.0.0-beta3
- 1.0.0-beta2
- 1.0.0-beta1
- dev-php_8
- dev-tweaks_coverage
- dev-github_actions
- dev-php8
- dev-adds_header_license
- dev-adds_laravel
- dev-adds_instrumentation_mysqli
- dev-13_adds_extra_support
This package is auto-updated.
Last update: 2024-09-17 21:33:59 UTC
README
Zipkin PHP 是 Zipkin 的官方 PHP 跟踪器实现,由 OpenZipkin 社区支持。
安装
composer require openzipkin/zipkin
设置
use Zipkin\Annotation; use Zipkin\Endpoint; use Zipkin\Samplers\BinarySampler; use Zipkin\TracingBuilder; use Zipkin\Reporters\Http; // First we create the endpoint that describes our service $endpoint = Endpoint::create('my_service'); $reporter = new Http(['endpoint_url' => 'http://myzipkin:9411/api/v2/spans']); $sampler = BinarySampler::createAsAlwaysSample(); $tracing = TracingBuilder::create() ->havingLocalEndpoint($endpoint) ->havingSampler($sampler) ->havingReporter($reporter) ->build(); $tracer = $tracing->getTracer(); ... $tracer->flush();
注意:对于更完整的客户端/服务器端示例,请查看 此存储库。
跟踪
跟踪器创建和连接跨度,这些跨度模拟了可能分布的工作的延迟。它可以采用抽样来减少进程中的开销或将发送到 Zipkin 的数据量减少。
跟踪器返回的跨度在完成时向 Zipkin 报告数据,如果不进行抽样则不执行任何操作。在启动跨度后,您可以注释感兴趣的事件或添加包含详细信息或查找键的标签。
跨度有一个上下文,它包括放置在表示分布式操作的树中的正确位置的跟踪标识符。
本地跟踪
在跟踪本地代码时,只需在跨度内运行它
$span = $tracer->newTrace(); $span->setName('encode'); $span->start(); try { doSomethingExpensive(); } finally { $span->finish(); }
在上面的示例中,跨度是跟踪的根。在许多情况下,您将是现有跟踪的一部分。在这种情况下,请调用 newChild
而不是 newTrace
$span = $tracer->newChild($root->getContext()); $span->setName('encode'); $span->start(); try { doSomethingExpensive(); } finally { $span->finish(); }
自定义跨度
一旦您有了跨度,您可以向它添加标签,这些标签可以用作查找键或详细信息。例如,您可能会添加一个包含您的运行时版本的标签。
$span->tag('http.status_code', '200');
RPC 跟踪
RPC 跟踪通常由拦截器自动执行。在幕后,它们添加与它们在 RPC 操作中角色相关的标签和事件。
以下是一个客户端跨度的示例
// before you send a request, add metadata that describes the operation $span = $tracer->newTrace(); $span->setName('get'); $span->setKind(Kind\CLIENT); $span->tag('http.status_code', '200'); $span->tag(Tags\HTTP_PATH, '/api'); $span->setRemoteEndpoint(Endpoint::create('backend', 127 << 24 | 1, null, 8080)); // when the request is scheduled, start the span $span->start(); // if you have callbacks for when data is on the wire, note those events $span->annotate(Annotation\WIRE_SEND); $span->annotate(Annotation\WIRE_RECV); // when the response is complete, finish the span $span->finish();
抽样
抽样可以用于减少收集和报告的数据量。当跨度未抽样时,它不会添加任何开销(noop)。
抽样是一个前置决策,这意味着在跟踪中的第一个操作中就做出报告数据的决策,并且该决策会向下传播。
默认情况下,有一个全局采样器,将单个速率应用于所有跟踪操作。《采样器》是您表示此的方式,并且默认为跟踪每个请求。
自定义抽样
您可能希望根据操作应用不同的策略。例如,您可能不希望跟踪对静态资源(如图像)的请求,或者您可能希望跟踪对新 api 的所有请求。
大多数用户将使用框架拦截器来自动化此类策略。以下是如何它们可能在内部工作的示例。
private function newTrace(Request $request) { $flags = SamplingFlags::createAsEmpty(); if (strpos($request->getUri(), '/experimental') === 0) { $flags = DefaultSamplingFlags::createAsSampled(); } else if (strpos($request->getUri(), '/static') === 0) { $flags = DefaultSamplingFlags::createAsSampled(); } return $tracer->newTrace($flags); }
传播
传播是必要的,以确保来自同一根的活动在同一个跟踪中收集在一起。最常用的传播方法是复制一个跟踪上下文,从发送 RPC 请求的客户端到接收它的服务器。
例如,当进行下游 Http 调用时,其跟踪上下文会随它一起发送,并以请求头的形式编码。
Client Span Server Span
┌──────────────────┐ ┌──────────────────┐
│ │ │ │
│ TraceContext │ Http Request Headers │ TraceContext │
│ ┌──────────────┐ │ ┌───────────────────┐ │ ┌──────────────┐ │
│ │ TraceId │ │ │ X-B3-TraceId │ │ │ TraceId │ │
│ │ │ │ │ │ │ │ │ │
│ │ ParentSpanId │ │ Extract │ X-B3-ParentSpanId │ Inject │ │ ParentSpanId │ │
│ │ ├─┼─────────>│ ├────────┼>│ │ │
│ │ SpanId │ │ │ X-B3-SpanId │ │ │ SpanId │ │
│ │ │ │ │ │ │ │ │ │
│ │ Sampled │ │ │ X-B3-Sampled │ │ │ Sampled │ │
│ └──────────────┘ │ └───────────────────┘ │ └──────────────┘ │
│ │ │ │
└──────────────────┘ └──────────────────┘
上面的名称来自 B3 Propagation,它是 Brave 内置的,并且在许多语言和框架中都有实现。
大多数用户将使用框架拦截器来自动化传播。以下是如何它们可能在内部工作的示例。
以下是客户端传播可能的样子
// configure a function that injects a trace context into a request $injector = $tracing->getPropagation()->getInjector(new RequestHeaders); // before a request is sent, add the current span's context to it $injector($span->getContext(), $request);
以下是服务器端传播可能的样子
// configure a function that extracts the trace context from a request $extractor = $tracing->getPropagation()->getExtractor(new RequestHeaders); $extracted = $extractor($request); $span = $tracer->newChild($extracted); $span->setKind(Kind\SERVER);
如果您没有使用框架或无法访问请求对象,您可以从 $_SERVER 变量中提取上下文
$extractor = $tracing->getPropagation()->getExtractor(new ServerHeaders); $extracted = $extractor($_SERVER);
提取传播上下文
《Extractor》从传入的请求或消息中读取跟踪标识符和采样状态。载体通常是请求对象或头信息。
SamplingFlags|TraceContext
通常仅与$tracer->newChild(extracted)
一起使用,除非你在客户端和服务器之间共享span ID。
实现传播
Extractor
将输出一个包含以下之一的SamplingFlags|TraceContext
:
- 如果存在跟踪和span ID,则为
TraceContext
。 - 如果不存在标识符,则为
SamplingFlags
。
当前span
Zipkin支持“当前span”的概念,它表示正在进行的操作。《Tracer::currentSpan()》可用于向span添加自定义标签,而《Tracer::nextSpan()》可用于创建任何正在进行的操作的子span。
当前span的一个常见用法是用于对RPC客户端进行检测。例如
/** * This http clients composes an http client using PSR7 */ class TraceClient implements ClientInterface { public function request($method, $uri = '', array $options = []) { /* Gets the child Span of the current one */ $span = $this->tracer->nextSpan(); $span->setKind(Zipkin\Kind\CLIENT); $span->tag(Tags\HTTP_PATH, $uri); try { $response = $this->client->request($method, $uri, $options); $span->tag(Tags\HTTP_STATUS_CODE, $response->getStatusCode()); return $response; catch (Throwable $e) { $span->setError($e); throw $e; } finally { $span->finish(); } } }
手动设置作用域中的span
当编写新的检测代码时,将创建的span放置在作用域中作为当前span是很重要的。
在边缘情况下,您可能需要临时清除当前span。例如,启动不应与当前请求关联的任务。为此,只需将null传递给openScope
即可。
检测
测试
可以通过以下方式运行测试:
composer test
而静态检查可以通过以下方式运行:
composer static-check