PHPackages                             cboxdk/statamic-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. cboxdk/statamic-telemetry

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

cboxdk/statamic-telemetry
=========================

Statamic overlay for cboxdk/laravel-telemetry: content-aware trace names, Stache and static-cache instrumentation, site context and user attribution.

v1.1.0(1mo ago)083↓27.8%MITPHPPHP ^8.3|^8.4|^8.5CI passing

Since Jul 3Pushed 1mo agoCompare

[ Source](https://github.com/cboxdk/statamic-telemetry)[ Packagist](https://packagist.org/packages/cboxdk/statamic-telemetry)[ RSS](/packages/cboxdk-statamic-telemetry/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (8)Dependencies (24)Versions (14)Used By (0)

Statamic Telemetry
==================

[](#statamic-telemetry)

Statamic overlay for [cboxdk/laravel-telemetry](https://github.com/cboxdk/laravel-telemetry): content-aware trace names, Stache and static-cache instrumentation, site context and user attribution — as a proper Statamic addon.

laravel-telemetry already traces requests, queries, queue jobs, cache and more. This addon teaches those traces Statamic's vocabulary:

- **Request span naming** — every Statamic frontend request goes through one catch-all route, so the default `METHOD /route/{pattern}` name collapses to a single useless value. Entry requests become `GET entry:{collection}.{blueprint}`, term requests `GET term:{taxonomy}` — bounded names, while `http.route`keeps the raw pattern.
- **Content attributes** — `statamic.entry.id`, `statamic.collection`, `statamic.blueprint`, `statamic.taxonomy`, `statamic.term.id` and `statamic.site` on the request root span.
- **Site context** — `statamic.site` as an ambient dimension on every span in the trace, propagated to queued jobs.
- **User attribution** — `enduser.roles`, `enduser.groups` and `enduser.super`for Statamic users (file or eloquent driven), on top of the core `enduser.id/type/guard`.
- **Static cache** — hit/miss/write outcome as `statamic.static_cache` on the root span, operation counters, and a fix for a subtle replay bug: the half-measure cacher snapshots response headers, so the addon strips the `X-Trace-Id` header before it is baked into the cached response and replayed to every visitor.
- **Stache** — cache keys classified into bounded groups (`stache.index`, `stache.item`, `stache.meta`, `static_cache`, `app`) so cache counters and spans don't drown in thousands of raw keys; warm/clear counters and warm duration.
- **Glide, forms, content changes** — counters per preset, per form, and per content type/action.
- **Antlers render spans** (opt-in) — a detail span per rendered view.
- **Observable gauges** (opt-in) — entries per collection, assets per container, user count, evaluated at scrape time.

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

[](#installation)

```
composer require cboxdk/statamic-telemetry:^0.2.0
```

> **`0.2.0`.** Tracks `cboxdk/laravel-telemetry`'s version line — the first release without a pre-release suffix, so no `minimum-stability`tweak is needed. Under SemVer 0.x, breaking changes bump the minor version; the metric and attribute surface is stable enough for production pilots.

Requires PHP 8.3+, Statamic 6 and cboxdk/laravel-telemetry ^0.2.0. Everything is on by default except Antlers view/tag spans and the gauges. Publish the config to change toggles:

```
php artisan vendor:publish --tag=statamic-telemetry-config
```

What you get
------------

[](#what-you-get)

### Spans &amp; attributes

[](#spans--attributes)

AttributeWhereValues`statamic.type`root span`entry`, `term`, `taxonomy``http.route`root span + request metriclogical content route: `entry:blog.article`, `term:topics`, `taxonomy:topics``http.route.template`root span (when overridden)raw Laravel template: `/{segments?}``statamic.entry.id` / `statamic.term.id`root spanid`statamic.collection` / `statamic.blueprint` / `statamic.taxonomy`root spanhandles`statamic.site`root span + all spans (context)site handle`statamic.static_cache`root span`hit`, `miss`, `write``enduser.roles` / `enduser.groups`root spansorted, comma-joined handles`enduser.super`root span`true` (only when super)`cache.key.group`cache spans (core)`stache.index`, `stache.item`, …`statamic.blink.hits` / `statamic.blink.misses`root span (tallies)per-request Blink memoization effectiveness`view.path` / `view.engine``view.render` detail spans (opt-in)relative path, `antlers``antlers.tag` / `antlers.method``antlers:{tag}` detail spans (opt-in)bounded tag name (`collection`, `partial`) + unbounded method (`blog`, `components/hero`)### Metrics

[](#metrics)

MetricTypeLabels`statamic.static_cache.operations`counter`operation`: hit, miss, write, invalidate, flush`statamic.stache.warms` / `statamic.stache.clears`counter—`statamic.stache.warm_duration`histogram (ms)—`statamic.glide.generations`counter`preset` (ad-hoc params → `custom`)`statamic.forms.submissions`counter`form``statamic.content.changes`counter`type`, `action``statamic.search.index_updates`counter`index``statamic.auth.events`counter`event`: impersonation, 2FA, registrations, password changes`statamic.glide.cache_clears`counter`scope`: all, asset`statamic.entries.count`gauge (opt-in)`collection``statamic.assets.count`gauge (opt-in)`container``statamic.users.count`gauge (opt-in)—Core cache counters additionally carry the `key_group` label from the classifier.

Grafana dashboard
-----------------

[](#grafana-dashboard)

The addon bundles a **Statamic** dashboard for the Grafana suite that ships with laravel-telemetry (`telemetry:dashboards`): static cache hit ratio and operations, Stache traffic by key group and warm duration, content changes, form submissions, Glide generations, the opt-in inventory gauges, and Tempo panels for content traces and slow uncached pages.

```
php artisan statamic-telemetry:dashboards            # import into http://localhost:3000
php artisan statamic-telemetry:dashboards --grafana=https://grafana.example.com --token=...
php artisan statamic-telemetry:dashboards --export=./grafana-provisioning
```

It carries the same `telemetry` tag as the core suite, so it appears as a tab alongside Overview, Requests, Jobs, etc. Panels are regenerated with `php resources/grafana/generate.php`.

The addon adds a **Telemetry** item to the Control Panel nav pointing at your telemetry UI — the in-app [`cboxdk/laravel-telemetry-ui`](https://github.com/cboxdk/laravel-telemetry-ui)dashboard automatically when installed (it has Statamic pages), or set `STATAMIC_TELEMETRY_UI_URL` for Grafana / a remote UI.

Browser tracing in Antlers
--------------------------

[](#browser-tracing-in-antlers)

laravel-telemetry's browser RUM ([`@cboxdk/telemetry-browser`](https://www.npmjs.com/package/@cboxdk/telemetry-browser)) in Antlers templates — drop it in your layout ``:

```
{{ telemetry:browser }}      {{# meta traceparent + the RUM script #}}
{{ telemetry:traceparent }}  {{# just the meta, if you load the script yourself #}}
```

Both are empty when the span ingest (`TELEMETRY_INGEST_SPANS`) or the trace is off. **Static caching is handled**: the per-request traceparent and `data-session` are stripped from cached pages by a Statamic replacer (like the CSRF one), so a cache hit never replays one visitor's server trace or analytics session to everyone — the RUM self-roots instead. Full-measure (file) hits are served without PHP, so they get a self-rooted browser trace with no server span; the strip happens once when the file is compiled. See [docs/browser-tracing](docs/browser-tracing.md).

Composing with your own hooks
-----------------------------

[](#composing-with-your-own-hooks)

laravel-telemetry's resolver hooks are single-slot — the last registration wins. This addon registers during boot, so if your app registers its own resolver it replaces the Statamic one. Delegate to the addon's public methods to compose:

```
use Cbox\StatamicTelemetry\Hooks;
use Cbox\StatamicTelemetry\Support\CacheKeys;
use Cbox\StatamicTelemetry\Support\Content;

Telemetry::resolveUserUsing(fn ($user, $guard) => [
    ...Hooks::userAttributes($user, $guard),
    'enduser.plan' => $user->plan ?? null,
]);

Telemetry::nameRequestsUsing(fn ($request, $response) =>
    $request->is('api/*') ? 'API '.$request->method() : Content::spanName($request)
);

Telemetry::classifyCacheKeysUsing(fn (string $store, string $key) =>
    str_starts_with($key, 'tenant:') ? 'tenant' : CacheKeys::classify($store, $key)
);

// The addon claims resolveRouteUsing (it overrides http.route with the
// logical content route). Compose if you want a different route identity:
Telemetry::resolveRouteUsing(fn ($request, $response) =>
    $request->is('api/*') ? 'api' : Content::routeLabel($request)
);
```

Design notes
------------

[](#design-notes)

- **Static cache drivers are subclassed, not decorated.** Statamic's middleware and replacers use `instanceof FileCacher/ApplicationCacher`checks to pick code paths; a decorator would silently change static caching behaviour. The addon re-registers the `file` and `application`drivers as tracing subclasses. Custom cacher drivers are not instrumented.
- **Full-measure hits are invisible.** With the `full` strategy, cached hits are served by the web server and never reach PHP — those requests produce no telemetry at all. Only PHP-served hits, misses and writes are recorded.
- **Cache hits keep the generic span name.** A static cache hit never reaches the frontend controller, so there is no entry to name the span by — hit traces are `GET /{pattern}` with `statamic.static_cache: hit`(and are fast). Content-named spans are the renders.
- **`http.route` is the content route.** Left alone, every frontend page shares the `/{segments?}` catch-all, so route tables and latency histograms collapse into one bucket. The addon uses the base package's `resolveRouteUsing()` hook to override `http.route` with the bounded logical route (`entry:blog.article`, `taxonomy:topics`), so the UI route table, Grafana and TraceQL all group by content — no per-tool change. The raw template is kept as `http.route.template`. Frontend 404s (broken links, bots) bucket as `not_found` instead of `/{segments?}`; cache hits stay `/{segments?}` (served before any content resolves — and fast). See [docs/design-notes](docs/design-notes.md#httproute-is-the-content-route-not-the-catch-all).
- **Trace header stripping.** The core package already skips the trace id header on `Cache-Control: public` responses (CDN caches). Statamic's half-measure cacher decides cacheability by its own rules and snapshots headers regardless, so the addon removes the header just before the snapshot — first visitors keep their header on file-measure, dynamic responses always keep it.
- **Augmentation is observed indirectly.** Statamic fires no events around field augmentation, so there is no direct per-field instrumentation. Its cost shows up in three places instead: the Blink tallies (augmentation memoization lives in Blink), the opt-in `antlers:{tag}` spans (tags are where augmentation work runs), and the opt-in `view.render` spans. Per-field visibility would need an upstream hook in statamic/cms.
- **Search queries are not counted.** Statamic fires `SearchIndexUpdated`for index writes (counted) but no event for queries — query latency is visible on the request span.
- **Telemetry never throws into the app.** The resolver hooks run inside laravel-telemetry's FailSafe; every event listener extends a `GuardedListener` base that wraps its body in the same guard. A broken listener can never break the entry save, upload or login it observes. Listeners also check their config toggle at event time, so toggles work at runtime and in tests.

More detail — the full metric/attribute/config catalog and the rationale behind each design decision — lives in [docs/](docs/index.md).

UI
--

[](#ui)

None yet — the addon is structured as a regular Statamic addon (`AddonServiceProvider`), so CP nav, widgets and routes can be added later without restructuring.

Testing
-------

[](#testing)

```
composer install
composer check   # pint + phpstan + pest
```

The test suite uses Statamic's `AddonTestCase` and `Telemetry::fake()`. Note for addon/package authors: after swapping in the fake, re-register the hooks (`Hooks::register($fake)`) — the boot-time registrations landed on the manager the fake replaces. See `tests/TestCase.php::fakeTelemetry()`.

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance91

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~1 days

Total

13

Last Release

36d ago

Major Versions

v0.2.2 → v1.0.02026-07-15

### Community

Maintainers

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

---

Top Contributors

[![sylvesterdamgaard](https://avatars.githubusercontent.com/u/2431914?v=4)](https://github.com/sylvesterdamgaard "sylvesterdamgaard (28 commits)")

---

Tags

Metricsopentelemetryotlpaddontelemetrystatamicprometheustraces

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/cboxdk-statamic-telemetry/health.svg)

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

###  Alternatives

[artprima/prometheus-metrics-bundle

Symfony 5.4/6.4/7.4/8.x Prometheus Metrics Bundle

1774.2M3](/packages/artprima-prometheus-metrics-bundle)[statamic-rad-pack/runway

Eloquently manage your database models in Statamic.

137236.2k8](/packages/statamic-rad-pack-runway)[open-telemetry/api

API for OpenTelemetry PHP.

2044.7M353](/packages/open-telemetry-api)[open-telemetry/sdk

SDK for OpenTelemetry PHP.

2430.8M443](/packages/open-telemetry-sdk)[worldia/instrumentation-bundle

Symfony opentelemetry auto-instrumentation: requests, commands, messenger, doctrine.

2877.2k](/packages/worldia-instrumentation-bundle)[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)
