PHPackages                             rasuvaeff/yii3-telemetry - 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

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

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

OpenTelemetry-based tracing facade for Yii3 applications

v1.1.1(1mo ago)04822BSD-3-ClausePHPPHP 8.3 - 8.5CI passing

Since Jul 10Pushed 6d agoCompare

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

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

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

[](#rasuvaeffyii3-telemetry)

[![Stable Version](https://camo.githubusercontent.com/c62e0f5014f8cf1ee69fe5aa559ab0dea70ae8adb6a8e4922f703035c06e9694/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7261737576616566662f796969332d74656c656d657472792e737667)](https://packagist.org/packages/rasuvaeff/yii3-telemetry)[![Total Downloads](https://camo.githubusercontent.com/87773a2ecbcb3afe80e7d055b0c9b3fa71a121a4c82941f173ea36fe4c817aa1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7261737576616566662f796969332d74656c656d657472792e737667)](https://packagist.org/packages/rasuvaeff/yii3-telemetry)[![Build](https://camo.githubusercontent.com/613062d98e1db381d24e67627d39a6e765d9cf5dd6f08e7deb71b4eb55e73da8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261737576616566662f796969332d74656c656d657472792f6275696c642e796d6c3f6272616e63683d6d6173746572)](https://github.com/rasuvaeff/yii3-telemetry/actions)[![Static Analysis](https://camo.githubusercontent.com/0df9bdf3c3231b9789cf8c26ec9264cb382b6b0463aaa3a8934cdf0a9af9236a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261737576616566662f796969332d74656c656d657472792f7374617469632d616e616c797369732e796d6c3f6272616e63683d6d6173746572)](https://github.com/rasuvaeff/yii3-telemetry/actions)[![Psalm Level](https://camo.githubusercontent.com/b837f56746c0e0ade3a4fb021825d42afe47dbd456f5355227c822e29b0dfb10/68747470733a2f2f73686570686572642e6465762f6769746875622f7261737576616566662f796969332d74656c656d657472792f6c6576656c2e737667)](https://shepherd.dev/github/rasuvaeff/yii3-telemetry)[![PHP](https://camo.githubusercontent.com/e6d9cdf0740c5c969ed31d81bb7bf9d535444f34f218facce599ac410b9ed9ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f7261737576616566662f796969332d74656c656d657472792f706870)](https://packagist.org/packages/rasuvaeff/yii3-telemetry)[![License](https://camo.githubusercontent.com/be5207e840b9d920770dafee39b0ac37ee5e14c3a4375817eb8bed92c18b81cd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7261737576616566662f796969332d74656c656d657472792e737667)](https://github.com/rasuvaeff/yii3-telemetry/blob/master/LICENSE.md)[Русская версия](README.ru.md)

Vendor-neutral tracing core for Yii3. One ergonomic call — `trace(name, callback)`— opens a span, runs your code, and closes the span, instead of the verbose OpenTelemetry span-builder. The exporter is a swappable backend.

> Using an AI coding assistant? [llms.txt](llms.txt) has a compact API reference you can pass as context. Projects using the [llm/skills](https://github.com/roxblnfk/skills) Composer plugin also get this package's agent skill synced into `.agents/skills/`automatically on install.

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

[](#requirements)

- PHP 8.3+ (64-bit — epoch nanoseconds exceed `PHP_INT_MAX` on 32-bit builds)
- `open-telemetry/api` ^1.5 (thin: interfaces + `NoopTracer`, no SDK)
- PSR-20 clock, PSR-3 log, PSR-7 http-message interfaces

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

[](#installation)

```
composer require rasuvaeff/yii3-telemetry
```

For real span export, add a backend (Sprint 2): `rasuvaeff/yii3-telemetry-otel`. Without one, bind the no-op provider (see [Wiring](#wiring-yiisoftconfig)).

Usage
-----

[](#usage)

### Trace a block of work

[](#trace-a-block-of-work)

```
use Rasuvaeff\Yii3Telemetry\SpanInterface;
use Rasuvaeff\Yii3Telemetry\TraceKind;
use Rasuvaeff\Yii3Telemetry\Tracer;

/** @var Tracer $tracer (injected) */
$order = $tracer->trace(
    name: 'checkout.process',
    callback: static function (SpanInterface $span) use ($cart): Order {
        $order = $cart->checkout();
        $span->setAttribute('order.id', $order->getId());

        return $order;
    },
    attributes: ['user.id' => $userId],
    scoped: true,
    traceKind: TraceKind::Internal,
);
```

The callback receives the active `SpanInterface` and its return value becomes the `trace()` return value.

### `trace()` contract (frozen at 1.0.0)

[](#trace-contract-frozen-at-100)

SituationBehaviourcallback returns a valuespan ends with its current status; value returnedcallback throws`recordException()`, status `Error`, span ends, the original exception is **re-thrown**`scoped: true` (default)span is `currentSpan()` during the callback; the previous span is restored afternested `trace()`the child inherits the parent's `traceId`, gets its own `spanId`span dropped / tracing disabledcallback still runs; `currentSpan()` returns a **non-recording** span, never `null``startNanos: `backdates the span start (unix-epoch nanoseconds) for work that logically began earlier — a worker receive timestamp, a queue enqueue time; `null` (default) = now`end()` is idempotent.

### Span

[](#span)

`SpanInterface` is what the callback receives:

MethodPurpose`setAttribute(string $key, bool|int|float|string|array|null $value)`attach a key/value`updateName(string $name)`rename the span`setStatus(SpanStatusCode $code, ?string $description = null)`set status`addEvent(string $name, array $attributes = [])`record a timestamped point-in-time annotation (an OTel span event: `retry`, `cache.miss`, …)`recordException(\Throwable $e)`record an exception`end()`finish (idempotent)`isRecording()``false` for non-recording spans`getTraceContext()`the span's `TraceContext`The concrete `Span` (recorded by `LogTracer`) additionally exposes getters: `getName()`, `getKind()`, `getStatus(): SpanStatus` (a value object pairing a `SpanStatusCode` with an optional description), `getAttributes()`, `getEvents(): list`, `getRecordedExceptions()`, `getDurationNanos()`, `hasEnded()`.

### Tracers

[](#tracers)

ClassUse`Tracer`DI facade; delegates to the active `TracerInterface` from the provider`NullTracer` / `NullTracerProvider`no-op; runs the callback with a non-recording span`LogTracer`dev tracer; records real spans and logs each finished span via PSR-3```
use Rasuvaeff\Yii3Telemetry\LogTracer;

$tracer = new LogTracer($psrLogger); // logs every finished span, no backend
```

### Context propagation (W3C Trace Context)

[](#context-propagation-w3c-trace-context)

```
use Rasuvaeff\Yii3Telemetry\TraceContextPropagator;

$propagator = new TraceContextPropagator();

// Incoming server request → context.
$context = $propagator->extract($serverRequest);

// Context → outgoing client request (adds the `traceparent` header).
$request = $propagator->inject($context, $clientRequest);
```

`extract` reads a `ServerRequestInterface`; `inject` writes an outgoing `RequestInterface`. A missing/malformed header yields `TraceContext::invalid()`.

For non-HTTP transports use the carrier-agnostic pair — a plain header map you can put into any envelope (queue message, AMQP header table, gRPC metadata):

```
// Producer: attach the current context to the message envelope.
$envelope['headers'] = $propagator->toHeaders($tracer->getContext());

// Consumer: restore it and open a Consumer span.
$context = $propagator->fromHeaders($message['headers'] ?? []);
```

`fromHeaders` matches names case-insensitively; an invalid context yields an empty map from `toHeaders`, so the round trip is always safe.

> **Queue instrumentation roadmap.** A ready-made `yiisoft/queue` middleware (Producer inject + Consumer span) is deferred until `yiisoft/queue` has a stable release — the carrier API above is the supported way to propagate a trace through any queue today.

### Clock

[](#clock)

`ClockInterface` extends PSR-20 with a monotonic reading — two clocks that must not be mixed:

- `now(): \DateTimeImmutable` — the wall clock (span start timestamp);
- `monotonicNanos(): int` — `hrtime`, for measuring durations.

`SystemClock` is the default (and is a valid PSR-20 clock).

Wiring (`yiisoft/config`)
-------------------------

[](#wiring-yiisoftconfig)

The core `config/di.php` binds **only** the facade (`Tracer`, `TracerInterface`). It never binds `TracerProviderInterface` — that swappable key is owned by exactly one source. With no backend installed, bind the no-op provider in your app:

```
// config/common/di.php
use Rasuvaeff\Yii3Telemetry\NullTracerProvider;
use Rasuvaeff\Yii3Telemetry\TracerProviderInterface;

return [
    TracerProviderInterface::class => NullTracerProvider::class,
];
```

Installing `yii3-telemetry-otel` provides the real binding instead — binding it in two vendor packages is a deliberate `yiisoft/config` `Duplicate key` error.

Instrumentation
---------------

[](#instrumentation)

Backend-agnostic instrumentation that records spans through the facade. Wire it **app-side** — never unconditionally in a package `di.php`, or the container would fatal when the subsystem isn't installed.

ClassWraps / listens toSpans`HttpClientSpanDecorator`a PSR-18 client`HTTP ` (+ `traceparent` injected)`TracingCacheDecorator`a PSR-16 cache`cache.``DbQueryProfiler``yiisoft/db` profiler`db.query` (parameterized SQL only)`ViewRenderSpanListener``yiisoft/view` PSR-14 events`view.render``TraceContextLogger`a PSR-3 loggeradds `trace_id`/`span_id` to log context`TraceIdResponseHeaderMiddleware`PSR-15 response`X-Trace-Id` response header (opt-in)```
// HTTP client (PSR-18) — inner client is wrapped
$client = new HttpClientSpanDecorator($innerClient, $tracer);

// Cache (PSR-16)
$cache = new TracingCacheDecorator($innerCache, $tracer);

// DB (yiisoft/db) — pass the semconv db.system for your driver (default 'sql')
$connection->setProfiler(new DbQueryProfiler($tracer, dbSystem: 'postgresql'));

// View (yiisoft/view) — register in config/events.php
BeforeRender::class => [[ViewRenderSpanListener::class, 'beforeRender']],
AfterRender::class  => [[ViewRenderSpanListener::class, 'afterRender']],
```

`DbQueryProfiler` and `ViewRenderSpanListener` bracket a subsystem's split begin/end hooks with `Tracer::startSpan()` (a manual span the caller ends). `yiisoft/db` and `yiisoft/view` are optional (`suggest`); their symbols are declared in `composer-require-checker.json`.

### Log correlation &amp; exposing the trace id

[](#log-correlation--exposing-the-trace-id)

```
// Wrap the application logger — every record inside an active trace gets
// trace_id / span_id in its context (existing keys are never overwritten):
$logger = new TraceContextLogger($innerLogger, $tracer);

// Opt-in: return the trace id to the client for support tickets. Place it
// AFTER the tracing middleware (inside the root span):
$middleware = new TraceIdResponseHeaderMiddleware($tracer);              // X-Trace-Id
$middleware = new TraceIdResponseHeaderMiddleware($tracer, 'Trace-Ref'); // custom name
```

Without an active valid trace context both are transparent: the log record and the response pass through unchanged.

Security
--------

[](#security)

- **SQL safety**: `DbQueryProfiler` puts only the **parameterized** SQL into `db.statement` — parameter values are never attached to a span. A debug opt-in for parameter values and a slow-query threshold are deliberately not implemented; if they land later, they will be off by default.
- `TraceContext` validates ids (hex32 / hex16) and flags (0..255) in its constructor; malformed propagation headers are rejected, not trusted.
- `trace()` never swallows exceptions — failures stay visible.

Examples
--------

[](#examples)

Runnable, server-independent scripts live in [`examples/`](examples/): `01_basic_trace.php`, `02_nested_trace.php`, `03_propagation.php`. See [`examples/README.md`](examples/README.md).

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

[](#development)

```
docker run --rm -v "$PWD":/app -w /app composer:2 composer build
```

Runs validate → normalize → require-checker → cs → psalm → tests (incl. property tests). `make build`, `make test`, `make mutation`, `make release-check`are also available.

License
-------

[](#license)

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

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance96

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 72% 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 (18 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (7 commits)")

---

Tags

distributed-tracingobservabilityopentelemetryphppsr-15spanstelemetrytracingyii3tracingopentelemetryotelobservabilityyii3

###  Code Quality

Static AnalysisPsalm, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.9k20.0M1.9k](/packages/cakephp-cakephp)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86337.5k](/packages/flow-php-flow)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k21](/packages/tempest-framework)[symfony/symfony

The Symfony PHP framework

31.4k87.4M2.2k](/packages/symfony-symfony)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.6k2.2M147](/packages/mcp-sdk)

PHPackages © 2026

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