{"id":20032059,"url":"https://github.com/openzipkin/zipkin-php","last_synced_at":"2025-04-08T09:05:33.792Z","repository":{"id":23430118,"uuid":"97314424","full_name":"openzipkin/zipkin-php","owner":"openzipkin","description":"Zipkin instrumentation for PHP","archived":false,"fork":false,"pushed_at":"2023-09-28T20:54:58.000Z","size":558,"stargazers_count":277,"open_issues_count":14,"forks_count":59,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-01T07:43:04.749Z","etag":null,"topics":["distributed-tracing","hacktoberfest","instrumentation","observability","openzipkin","php","zipkin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openzipkin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-15T12:26:36.000Z","updated_at":"2025-03-11T06:16:23.000Z","dependencies_parsed_at":"2024-06-18T11:08:59.350Z","dependency_job_id":"2392202c-dcad-424c-932e-d834c7898029","html_url":"https://github.com/openzipkin/zipkin-php","commit_stats":{"total_commits":211,"total_committers":21,"mean_commits":"10.047619047619047","dds":0.1943127962085308,"last_synced_commit":"6ad732249a0facb785eda3cad278c7a88d7a3850"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openzipkin%2Fzipkin-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openzipkin%2Fzipkin-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openzipkin%2Fzipkin-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openzipkin%2Fzipkin-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openzipkin","download_url":"https://codeload.github.com/openzipkin/zipkin-php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247809963,"owners_count":20999816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["distributed-tracing","hacktoberfest","instrumentation","observability","openzipkin","php","zipkin"],"created_at":"2024-11-13T09:35:46.322Z","updated_at":"2025-04-08T09:05:33.761Z","avatar_url":"https://github.com/openzipkin.png","language":"PHP","readme":"# Zipkin PHP\n\n![CI](https://github.com/openzipkin/zipkin-php/workflows/CI/badge.svg)\n[![Latest Stable Version](https://poser.pugx.org/openzipkin/zipkin/v/stable)](https://packagist.org/packages/openzipkin/zipkin)\n[![Coverage Status](https://coveralls.io/repos/github/openzipkin/zipkin-php/badge.svg)](https://coveralls.io/github/openzipkin/zipkin-php)\n[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.4-8892BF.svg)](https://php.net/)\n[![Total Downloads](https://poser.pugx.org/openzipkin/zipkin/downloads)](https://packagist.org/packages/openzipkin/zipkin)\n[![License](https://img.shields.io/packagist/l/openzipkin/zipkin.svg)](https://github.com/openzipkin/zipkin-php/blob/master/LICENSE)\n\nZipkin PHP is the official PHP Tracer implementation for Zipkin, supported by the OpenZipkin community.\n\n## Installation\n\n```bash\ncomposer require openzipkin/zipkin\n```\n\n## Setup\n\n```php\nuse Zipkin\\Annotation;\nuse Zipkin\\Endpoint;\nuse Zipkin\\Samplers\\BinarySampler;\nuse Zipkin\\TracingBuilder;\nuse Zipkin\\Reporters\\Http;\n\n// First we create the endpoint that describes our service\n$endpoint = Endpoint::create('my_service');\n\n$reporter = new Http(['endpoint_url' =\u003e 'http://myzipkin:9411/api/v2/spans']);\n$sampler = BinarySampler::createAsAlwaysSample();\n$tracing = TracingBuilder::create()\n    -\u003ehavingLocalEndpoint($endpoint)\n    -\u003ehavingSampler($sampler)\n    -\u003ehavingReporter($reporter)\n    -\u003ebuild();\n\n$tracer = $tracing-\u003egetTracer();\n\n...\n\n$tracer-\u003eflush();\n```\n\n**Obs.** for a more complete frontend/backend example, check [this repository](https://github.com/openzipkin/zipkin-php-example).\n\n## Tracing\n\nThe tracer creates and joins spans that model the latency of potentially\ndistributed work. It can employ sampling to reduce overhead in process\nor to reduce the amount of data sent to Zipkin.\n\nSpans returned by a tracer report data to Zipkin when finished, or do\nnothing if unsampled. After starting a span, you can annotate events of\ninterest or add tags containing details or lookup keys.\n\nSpans have a context which includes trace identifiers that place it at\nthe correct spot in the tree representing the distributed operation.\n\n### Local Tracing\n\nWhen tracing local code, just run it inside a span\n\n```php\n$span = $tracer-\u003enewTrace();\n$span-\u003esetName('encode');\n$span-\u003estart();\n\ntry {\n  doSomethingExpensive();\n} finally {\n  $span-\u003efinish();\n}\n```\n\nIn the above example, the span is the root of the trace. In many cases,\nyou will be a part of an existing trace. When this is the case, call\n`newChild` instead of `newTrace`\n\n```php\n$span = $tracer-\u003enewChild($root-\u003egetContext());\n$span-\u003esetName('encode');\n$span-\u003estart();\ntry {\n  doSomethingExpensive();\n} finally {\n  $span-\u003efinish();\n}\n```\n\n### Customizing spans\n\nOnce you have a span, you can add tags to it, which can be used as lookup\nkeys or details. For example, you might add a tag with your runtime\nversion.\n\n```php\n$span-\u003etag('http.status_code', '200');\n```\n\n### RPC tracing\n\nRPC tracing is often done automatically by interceptors. Under the scenes,\nthey add tags and events that relate to their role in an RPC operation.\n\nHere's an example of a client span:\n\n```php\n// before you send a request, add metadata that describes the operation\n$span = $tracer-\u003enewTrace();\n$span-\u003esetName('get');\n$span-\u003esetKind(Kind\\CLIENT);\n$span-\u003etag('http.status_code', '200');\n$span-\u003etag(Tags\\HTTP_PATH, '/api');\n$span-\u003esetRemoteEndpoint(Endpoint::create('backend', 127 \u003c\u003c 24 | 1, null, 8080));\n\n// when the request is scheduled, start the span\n$span-\u003estart();\n\n// if you have callbacks for when data is on the wire, note those events\n$span-\u003eannotate(Annotation\\WIRE_SEND);\n$span-\u003eannotate(Annotation\\WIRE_RECV);\n\n// when the response is complete, finish the span\n$span-\u003efinish();\n```\n\n## Sampling\n\nSampling may be employed to reduce the data collected and reported out\nof process. When a span isn't sampled, it adds no overhead (noop).\n\nSampling is an up-front decision, meaning that the decision to report\ndata is made at the first operation in a trace, and that decision is\npropagated downstream.\n\nBy default, there's a global sampler that applies a single rate to all\ntraced operations. `Sampler` is how you indicate this,\nand it defaults to trace every request.\n\n### Custom sampling\n\nYou may want to apply different policies depending on what the operation\nis. For example, you might not want to trace requests to static resources\nsuch as images, or you might want to trace all requests to a new api.\n\nMost users will use a framework interceptor which automates this sort of\npolicy. Here's how they might work internally.\n\n```php\nprivate function newTrace(Request $request) {\n  $flags = SamplingFlags::createAsEmpty();\n  if (strpos($request-\u003egetUri(), '/experimental') === 0) {\n    $flags = DefaultSamplingFlags::createAsSampled();\n  } else if (strpos($request-\u003egetUri(), '/static') === 0) {\n    $flags = DefaultSamplingFlags::createAsSampled();\n  }\n  return $tracer-\u003enewTrace($flags);\n}\n```\n\n## Propagation\n\nPropagation is needed to ensure activity originating from the same root\nare collected together in the same trace. The most common propagation\napproach is to copy a trace context from a client sending an RPC request\nto a server receiving it.\n\nFor example, when an downstream Http call is made, its trace context is\nsent along with it, encoded as request headers:\n\n```\n   Client Span                                                Server Span\n┌──────────────────┐                                       ┌──────────────────┐\n│                  │                                       │                  │\n│   TraceContext   │           Http Request Headers        │   TraceContext   │\n│ ┌──────────────┐ │          ┌───────────────────┐        │ ┌──────────────┐ │\n│ │ TraceId      │ │          │ X-B3-TraceId      │        │ │ TraceId      │ │\n│ │              │ │          │                   │        │ │              │ │\n│ │ ParentSpanId │ │ Extract  │ X-B3-ParentSpanId │ Inject │ │ ParentSpanId │ │\n│ │              ├─┼─────────\u003e│                   ├────────┼\u003e│              │ │\n│ │ SpanId       │ │          │ X-B3-SpanId       │        │ │ SpanId       │ │\n│ │              │ │          │                   │        │ │              │ │\n│ │ Sampled      │ │          │ X-B3-Sampled      │        │ │ Sampled      │ │\n│ └──────────────┘ │          └───────────────────┘        │ └──────────────┘ │\n│                  │                                       │                  │\n└──────────────────┘                                       └──────────────────┘\n```\n\nThe names above are from [B3 Propagation](https://github.com/openzipkin/b3-propagation),\nwhich is built-in to Brave and has implementations in many languages and\nframeworks.\n\nMost users will use a framework interceptor which automates propagation.\nHere's how they might work internally.\n\nHere's what client-side propagation might look like\n\n```php\n// configure a function that injects a trace context into a request\n$injector = $tracing-\u003egetPropagation()-\u003egetInjector(new RequestHeaders);\n\n// before a request is sent, add the current span's context to it\n$injector($span-\u003egetContext(), $request);\n```\n\nHere's what server-side propagation might look like\n\n```php\n// configure a function that extracts the trace context from a request\n$extractor = $tracing-\u003egetPropagation()-\u003egetExtractor(new RequestHeaders);\n$extracted = $extractor($request);\n\n$span = $tracer-\u003enewChild($extracted);\n$span-\u003esetKind(Kind\\SERVER);\n```\n\nIf you aren't using a framework or don't have access to the Request object, you\ncan extract the context from the $_SERVER variable\n\n```php\n$extractor = $tracing-\u003egetPropagation()-\u003egetExtractor(new ServerHeaders);\n$extracted = $extractor($_SERVER);\n```\n\n### Extracting a propagated context\n\nThe `Extractor` reads trace identifiers and sampling status\nfrom an incoming request or message. The carrier is usually a request object\nor headers.\n\n`SamplingFlags|TraceContext` is usually only used with `$tracer-\u003enewChild(extracted)`, unless you are\nsharing span IDs between a client and a server.\n\n### Implementing Propagation\n\n`Extractor` will output a `SamplingFlags|TraceContext` with one of the following:\n\n* `TraceContext` if trace and span IDs were present.\n* `SamplingFlags` if no identifiers were present\n\n## Current Span\n\nZipkin supports a \"current span\" concept which represents the in-flight\noperation. `Tracer::currentSpan()` can be used to add custom tags to a\nspan and `Tracer::nextSpan()` can be used to create a child of whatever\nis in-flight.\n\nA common use case for the current span is to instrument RPC clients. For example:\n\n```php\n/**\n  * This http clients composes an http client using PSR7\n  */\nclass TraceClient implements ClientInterface\n{\n    public function request($method, $uri = '', array $options = [])\n    {\n        /* Gets the child Span of the current one */\n        $span = $this-\u003etracer-\u003enextSpan();\n        $span-\u003esetKind(Zipkin\\Kind\\CLIENT);\n        $span-\u003etag(Tags\\HTTP_PATH, $uri);\n\n        try {\n            $response = $this-\u003eclient-\u003erequest($method, $uri, $options);\n            $span-\u003etag(Tags\\HTTP_STATUS_CODE, (string) $response-\u003egetStatusCode());\n\n            return $response;\n        catch (Throwable $e) {\n            $span-\u003esetError($e);\n            throw $e;\n        } finally {\n            $span-\u003efinish();\n        }\n    }\n}\n```\n\n### Setting a span in scope manually\n\nWhen writing new instrumentation, it is important to place a span you\ncreated in scope as the current span.\n\nIn edge cases, you may need to clear the current span temporarily. For\nexample, launching a task that should not be associated with the current\nrequest. To do this, simply pass null to `openScope`.\n\n## Instrumentation\n\n- [PSR18 HTTP Client](src/Zipkin/Instrumentation/Http/Client/Psr18)\n- [PSR15 HTTP Server](src/Zipkin/Instrumentation/Http/Server/Psr15)\n\n## Tests\n\nTests can be run by\n\n```bash\ncomposer test\n```\n\nWhereas static checks can be run by:\n\n```bash\ncomposer static-check\n```\n\n## Reference\n\n* [Instrumenting a library](http://zipkin.io/pages/instrumenting.html)\n* [openzipkin/zipkin-api](https://github.com/openzipkin/zipkin-api)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenzipkin%2Fzipkin-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenzipkin%2Fzipkin-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenzipkin%2Fzipkin-php/lists"}