PHPackages                             rasuvaeff/yii3-telemetry-otel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. rasuvaeff/yii3-telemetry-otel

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

rasuvaeff/yii3-telemetry-otel
=============================

OpenTelemetry tracing backend for rasuvaeff/yii3-telemetry (Yii3)

v1.0.2(1mo ago)0119[1 PRs](https://github.com/rasuvaeff/yii3-telemetry-otel/pulls)1BSD-3-ClausePHPPHP 8.3 - 8.5CI passing

Since Jul 10Pushed 3d agoCompare

[ Source](https://github.com/rasuvaeff/yii3-telemetry-otel)[ Packagist](https://packagist.org/packages/rasuvaeff/yii3-telemetry-otel)[ Docs](https://github.com/rasuvaeff/yii3-telemetry-otel)[ RSS](/packages/rasuvaeff-yii3-telemetry-otel/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (44)Versions (4)Used By (1)

rasuvaeff/yii3-telemetry-otel
=============================

[](#rasuvaeffyii3-telemetry-otel)

[![Stable Version](https://camo.githubusercontent.com/e520feb81d24c62bc56e483b2a770f61d14f55452add2afe601acf91f2eb4888/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7261737576616566662f796969332d74656c656d657472792d6f74656c2e737667)](https://packagist.org/packages/rasuvaeff/yii3-telemetry-otel)[![Total Downloads](https://camo.githubusercontent.com/3b29b16de8857ef01df65174e5805fd3501a34bdca621c5e54b7418b4177b7a0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7261737576616566662f796969332d74656c656d657472792d6f74656c2e737667)](https://packagist.org/packages/rasuvaeff/yii3-telemetry-otel)[![Build](https://camo.githubusercontent.com/1d084af46889902f79fa11d7ed15fecd09bd453ab45e13bd1e9a915dfac2f6bf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261737576616566662f796969332d74656c656d657472792d6f74656c2f6275696c642e796d6c3f6272616e63683d6d6173746572)](https://github.com/rasuvaeff/yii3-telemetry-otel/actions)[![Static Analysis](https://camo.githubusercontent.com/03a9237fba4c87ef29b88bf78bc633c0cd32705936e9613fdcd5ddd06fafa69b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261737576616566662f796969332d74656c656d657472792d6f74656c2f7374617469632d616e616c797369732e796d6c3f6272616e63683d6d6173746572)](https://github.com/rasuvaeff/yii3-telemetry-otel/actions)[![Psalm Level](https://camo.githubusercontent.com/ee9225e0b2da899b4c30617bc6e2b0cc3c0f64418886e6fefc480b7a3cbfe3b1/68747470733a2f2f73686570686572642e6465762f6769746875622f7261737576616566662f796969332d74656c656d657472792d6f74656c2f6c6576656c2e737667)](https://shepherd.dev/github/rasuvaeff/yii3-telemetry-otel)[![PHP](https://camo.githubusercontent.com/c6c2b5182b5afd0cdf2d9f8b5c9829ba7f35050d8f2d2c6563a80a96dbf0ddc3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f7261737576616566662f796969332d74656c656d657472792d6f74656c2f706870)](https://packagist.org/packages/rasuvaeff/yii3-telemetry-otel)[![License](https://camo.githubusercontent.com/20d4a021d9a4441a7fb29094b6cba0b0a604c5a7226001d1901b2c5b3764b254/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7261737576616566662f796969332d74656c656d657472792d6f74656c2e737667)](https://github.com/rasuvaeff/yii3-telemetry-otel/blob/master/LICENSE.md)[Русская версия](README.ru.md)

OpenTelemetry tracing backend for [`rasuvaeff/yii3-telemetry`](https://github.com/rasuvaeff/yii3-telemetry). It turns the core `Tracer` facade into real spans exported over OTLP to an OpenTelemetry Collector, plus a PSR-15 root-span middleware and W3C context propagation.

> Using an AI coding assistant? [llms.txt](llms.txt) has a compact API reference you can pass as context.

Requirements
------------

[](#requirements)

- PHP 8.3+ (64-bit)
- `rasuvaeff/yii3-telemetry` ^1.0
- `open-telemetry/sdk` ^1.7, `open-telemetry/exporter-otlp` ^1.4
- A PSR-18 HTTP client for OTLP export (e.g. `guzzlehttp/guzzle`)

Installation
------------

[](#installation)

```
composer require rasuvaeff/yii3-telemetry-otel guzzlehttp/guzzle
```

Installing this package binds the swappable `TracerProviderInterface` in the core — the `Tracer` facade now produces exported spans. Do **not** also bind the provider yourself (that is a deliberate `yiisoft/config` `Duplicate key` error).

Composer will ask to trust the `php-http/discovery` and `tbachert/spi` plugins (transitive OpenTelemetry dependencies) — answer yes, or preconfigure them in `config.allow-plugins`.

Usage
-----

[](#usage)

### Wire it (yiisoft/config)

[](#wire-it-yiisoftconfig)

The package ships `config/di.php`, `config/di-web.php`, and `config/params.php`. Configure the collector endpoint and service name via env vars (standard OTel names):

```
OTEL_SERVICE_NAME=checkout-api
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
```

Add `OtelMiddleware` to your middleware stack (typically first) so every request gets a SERVER root span that continues any incoming distributed trace.

Operational toggles in `params.php` (overridable in your app params):

ParamDefaultMeaning`enabled``true` (honours `OTEL_SDK_DISABLED=true`)`false` binds the no-op `NullTracerProvider` — nothing is built or exported, no error-log noise from an unreachable collector`content_type``application/x-protobuf` (honours `OTEL_EXPORTER_OTLP_PROTOCOL`: `http/json` → JSON)OTLP/HTTP payload encoding for a verified OTLP receiver such as the OTel Collector, Tempo, or Jaeger`excluded_paths``[]`exact request paths `OtelMiddleware` skips — scrape/probe endpoints (`/metrics`, `/health`): Prometheus polling every few seconds floods the tracing backend with identical traces`capture_query``true``url.query` on the root span; values of sensitive-looking keys (`password`, `token`, `api_key`, …) are replaced by `***` at every nesting level`capture_request_params``false` — **opt in consciously** (request payloads may carry personal data)records each query / form / top-level JSON-body parameter as `http.request.param.`; sensitive keys masked, values truncated to 200 chars, JSON bodies over 8 KiB skipped`batch``true`batch span processor (see flushing below)`register_shutdown_flush``true`registers a shutdown hook that flushes the batch processor — the correct default on php-fpm and CLI; disable on RoadRunner/Swoole if you flush via `SpanFlusher` on a timer`finish_request_before_flush``true`calls `fastcgi_finish_request()` before the flush, so the client never waits for the OTLP round-trip (~100 ms measured without it — Yii3's SAPI emitter does not finish the request itself). Disable only if other shutdown functions still write to the response### Span names &amp; `http.route`

[](#span-names--httproute)

Span naming follows the OTel HTTP semconv: `{method} {route}` with a route template (`GET /users/{id}`), plain `{method}` otherwise — never the raw path (one span name per user id would wreck operation search in Tempo/Jaeger; the raw path is always in the `url.path` attribute). Wire the router-aware resolver app-side (it needs `yiisoft/router`, which is optional):

```
// config/common/di.php
use Rasuvaeff\Yii3TelemetryOtel\CurrentRouteNameResolver;
use Rasuvaeff\Yii3TelemetryOtel\RouteNameResolverInterface;

return [
    RouteNameResolverInterface::class => CurrentRouteNameResolver::class,
];
```

`CurrentRouteNameResolver` reads the matched `yiisoft/router` pattern after the handler ran, so the tracing middleware can stay first in the stack. Unmatched requests (404s, scanners) keep the bare `{method}` name. A custom resolver is a one-method interface: `resolve(ServerRequestInterface): ?string`.

### Sampling

[](#sampling)

The provider uses the SDK sampler configuration — the standard OTel env vars:

```
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1   # keep 10% of new traces
```

Unset, it defaults to `parentbased_always_on` (trace everything, honour the incoming decision). To hardcode a sampler instead, pass it to the factory: `new OtelTracerProviderFactory(serviceName: '...', sampler: new AlwaysOffSampler())`. A dropped trace still runs your callback — `$span` is simply non-recording (the frozen core contract).

### Build a provider manually

[](#build-a-provider-manually)

```
use Rasuvaeff\Yii3TelemetryOtel\OtelTracerProvider;
use Rasuvaeff\Yii3TelemetryOtel\OtelTracerProviderFactory;
use Rasuvaeff\Yii3TelemetryOtel\OtlpExporterFactory;

$exporter = (new OtlpExporterFactory())->create('http://collector:4318');
$sdkProvider = (new OtelTracerProviderFactory(serviceName: 'checkout-api'))->create($exporter);

$tracer = (new OtelTracerProvider($sdkProvider))->getTracer();
$tracer->trace('checkout.process', static function ($span): void {
    $span->setAttribute('order.id', 'ORD-1');
});
```

The `$tracer` is a core `TracerInterface` — the frozen `trace()` contract applies (returns the callback value; on exception records it, sets status Error, ends, re-throws; nested spans inherit the parent trace id).

### Classes

[](#classes)

ClassPurpose`OtelTracerProvider`core `TracerProviderInterface` over the OTel SDK`OtelTracer` / `OtelSpan`adapters: core facade → OTel span`OtelTracerProviderFactory`builds an SDK `TracerProvider` from an exporter (batch by default)`OtlpExporterFactory`builds the OTLP/HTTP span exporter`RouteNameResolverInterface` / `CurrentRouteNameResolver`route-template span names (`{method} {route}`) — see above`ConsoleCommandSpanListener`root span per console command (cron) — see Console commands`OtelMiddleware`PSR-15 SERVER root span + incoming-context extraction`TraceContextExtractor` / `TraceContextInjector`W3C context in / out`SpanFlusher``forceFlush()` for long-running workers### Ending spans vs flushing the exporter

[](#ending-spans-vs-flushing-the-exporter)

Middleware ends the root span in `finally` every request (no span leak). Flushing the batch exporter is **separate** — `new TracerProvider(...)` registers **no**automatic shutdown flush, so with `register_shutdown_flush: true` (the default) the DI wiring registers one for you:

RuntimeWith the default `register_shutdown_flush: true`**php-fpm**The hook runs at the **end of every request**, after the response was sent with `fastcgi_finish_request` — one OTLP round-trip per request. That is the only correct option on fpm: there is no user-land worker-shutdown hook, and batch-buffered spans are otherwise **lost** when fpm recycles the worker. (`batch: false` / `SimpleSpanProcessor` is the alternative: export per span)**RoadRunner / Swoole / FrankenPHP**The hook fires once at worker exit — safe, but consider `register_shutdown_flush: false` + `SpanFlusher::flush()` on a timer / every N requests, so a crash loses at most one interval**CLI / cron**The hook fires once at process exit — exactly right```
use Rasuvaeff\Yii3TelemetryOtel\SpanFlusher;

$flusher = new SpanFlusher($sdkProvider);
// php-fpm / CLI:
register_shutdown_function(static fn (): bool => $flusher->flush());
// RoadRunner: call $flusher->flush() on worker stop instead.
```

### Console commands

[](#console-commands)

`OtelMiddleware` is web-only. For console commands (cron!) register `ConsoleCommandSpanListener` — it brackets `ApplicationStartup`/`ApplicationShutdown`in an ACTIVATED root span `console `, so DB/HTTP instrumentation spans become its children instead of flooding the backend with root-less `db.query`traces. A non-zero exit code marks the span as an error.

```
// config/console/events.php (needs yiisoft/yii-console — optional dep)
use Rasuvaeff\Yii3TelemetryOtel\ConsoleCommandSpanListener;
use Yiisoft\Yii\Console\Event\ApplicationShutdown;
use Yiisoft\Yii\Console\Event\ApplicationStartup;

return [
    ApplicationStartup::class => [[ConsoleCommandSpanListener::class, 'onStartup']],
    ApplicationShutdown::class => [[ConsoleCommandSpanListener::class, 'onShutdown']],
];
```

For ad-hoc scripts without yii-console, `trace()` still works:

```
$tracer->trace('cron.sync-orders', fn (SpanInterface $span) => $command->run(), traceKind: TraceKind::Internal);
```

Security
--------

[](#security)

- Distributed-trace headers are validated by the core propagator; malformed `traceparent` is ignored, not trusted.
- No credentials are placed in URLs; the OTLP endpoint is configuration.
- The middleware records `http.request.method`, `url.path`, `server.address`, `http.response.status_code` — avoid adding high-cardinality or sensitive attributes.

Examples
--------

[](#examples)

Runnable scripts in [`examples/`](examples/): in-memory export, the middleware, and OTLP provider setup. See [`examples/README.md`](examples/README.md). A full-stack `docker-compose` (collector + Tempo + Grafana) lives in [`examples/docker-compose/`](examples/docker-compose/).

### OTLP smoke check

[](#otlp-smoke-check)

Start that stack, emit a uniquely named span, then verify that Tempo indexed it:

```
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 php examples/04_otlp_smoke.php
curl -fsSG http://localhost:3200/api/search \
  --data-urlencode 'q={ name = "yii3-telemetry-otel.smoke" }'
```

The Tempo response must contain a trace (or find the same span in Grafana at `http://localhost:3000`). An exporter HTTP 2xx alone is insufficient: a generic HTTP dump endpoint can accept the payload without decoding it as OTLP.

### Dependency analysers

[](#dependency-analysers)

This leaf package is selected by the root application through config-plugin and may legitimately have no class reference in an autoloaded source directory. Keep the direct dependency: the application, not a core package, selects the backend or bridge. Scope the Composer Dependency Analyser exception to this package:

```
use ShipMonk\ComposerDependencyAnalyser\Config\Configuration;
use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;

return (new Configuration())->ignoreErrorsOnPackage(
    'rasuvaeff/yii3-telemetry-otel',
    [ErrorType::UNUSED_DEPENDENCY],
);
```

`composer-require-checker` detects used but undeclared symbols, not unused packages, so this config-only dependency needs no require-checker suppression.

Development
-----------

[](#development)

The core is resolved via a path repository during local development, so run Docker with the **monorepo root** mounted as `/repo`:

```
docker run --rm -v /path/to/monorepo:/repo -w /repo/yii3-telemetry-otel \
  composer:2 composer build
```

See [AGENTS.md](AGENTS.md) for the full command set and the publish checklist.

License
-------

[](#license)

BSD-3-Clause. See [LICENSE.md](LICENSE.md).

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance97

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 77.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Total

3

Last Release

33d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b0812d5572a7041dfe36e222d295b2e6dc55833a605350fcde58a51a5965ed30?d=identicon)[rasuvaeff](/maintainers/rasuvaeff)

---

Top Contributors

[![rasuvaeff](https://avatars.githubusercontent.com/u/1352718?v=4)](https://github.com/rasuvaeff "rasuvaeff (21 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (6 commits)")

---

Tags

distributed-tracingobservabilityopentelemetryotlpphppsr-15telemetrytracingyii3tracingopentelemetryotelbackendobservabilityyii3

###  Code Quality

Static AnalysisPsalm, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rasuvaeff-yii3-telemetry-otel/health.svg)

```
[![Health](https://phpackages.com/badges/rasuvaeff-yii3-telemetry-otel/health.svg)](https://phpackages.com/packages/rasuvaeff-yii3-telemetry-otel)
```

###  Alternatives

[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

173666.7k1](/packages/keepsuit-laravel-opentelemetry)[cakephp/cakephp

The CakePHP framework

8.9k20.0M1.9k](/packages/cakephp-cakephp)[traceway/opentelemetry-symfony

Pure-PHP OpenTelemetry instrumentation for Symfony — automatic HTTP, Console, HttpClient, Messenger, Doctrine DBAL, Cache, Twig tracing and Monolog log-trace correlation with response propagation, a lightweight Tracing helper, route templates, and semantic conventions. No C extension required (ext-protobuf recommended for production).

8322.8k](/packages/traceway-opentelemetry-symfony)[open-telemetry/sdk

SDK for OpenTelemetry PHP.

2430.8M445](/packages/open-telemetry-sdk)[friendsofopentelemetry/opentelemetry-bundle

Traces, metrics, and logs instrumentation within your Symfony application

6812.2k](/packages/friendsofopentelemetry-opentelemetry-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
