Configuration reference
Configuration reference
The package ships a fully-commented config/telemetry-ui.php. It works out of
the box with three env vars (metrics/traces/logs URLs); everything else has a
sensible default. Publish it only if you need to change something not reachable
by an env var:
php artisan vendor:publish --tag=telemetry-ui-config
This page is the exhaustive reference. Each key lists its default and the env var (if any) that overrides it without publishing.
Core
| Key | Env | Default | Notes |
|---|---|---|---|
enabled |
TELEMETRY_UI_ENABLED |
true |
Master switch. When off, the package registers no routes (SPA, API or assets) or MCP server — completely inert (e.g. on queue workers). Boot stays cheap either way. |
path |
TELEMETRY_UI_PATH |
telemetry-ui |
URL prefix the dashboard is served from; the API lives under {path}/api/v2 and the built assets under {path}/build. Deliberately not telemetry so it doesn't clash with the /telemetry/metrics scrape endpoint cboxdk/laravel-telemetry registers. |
ignore_own_requests |
TELEMETRY_UI_IGNORE_OWN_REQUESTS |
true |
Asks cboxdk/laravel-telemetry (Telemetry::ignorePaths()) not to trace the dashboard's own page loads and API calls ({path} and {path}/*), so browsing the dashboard never floods the app's request data. Registered when the telemetry manager resolves; no effect when mounted at the site root. |
domain |
TELEMETRY_UI_DOMAIN |
null |
Optional domain to pin the routes to. |
middleware |
— | ['web'] |
Middleware on every dashboard and API route. The package always appends its own Authorize middleware (checks the viewTelemetryUi gate), so you don't list it. The build/* asset route skips the gate and the throttle. |
throttle |
TELEMETRY_UI_THROTTLE |
600,1 |
Rate limit as maxAttempts,decayMinutes. The SPA sends one API request per panel, facet list and Explore query (and again on each auto-refresh tick), so the budget is per request, not per page. Set to null / empty to disable. |
copy_link |
TELEMETRY_UI_COPY_LINK |
true |
The header button that copies a shareable URL for the current view. Turn it off where the URL can't travel — a desktop host on 127.0.0.1:<random port> copies a link only that machine can open. |
timezone |
TELEMETRY_UI_TIMEZONE |
— | The zone times are shown in until a viewer picks their own in the header. Empty means each viewer's browser zone, so times read as local time. An IANA name (UTC, Europe/Copenhagen) gives everyone the same clock. The SPA sends the viewer's zone as X-Timezone, and the API formats its own times in it; without that header (a call by hand, MCP) this default applies, then app.timezone. |
brand.name / brand.logo / brand.accent |
TELEMETRY_UI_BRAND_NAME / _LOGO / _ACCENT |
app name / — / — | White-label the shell: rail name, logo image URL, accent colour. There are no views to override in v2; for more, read the JSON API. |
brand.credit |
TELEMETRY_UI_BRAND_CREDIT |
true |
The small "Powered by Cbox" link at the foot of the main navigation (the icon rail). Turn it off for a fully white-labelled dashboard. |
dimensions.label_ttl |
TELEMETRY_UI_LABEL_TTL |
300 |
How long a name from TelemetryUi::resolve() is cached per value (misses included). 0 disables caching. See dimensions. |
analytics.internal_hosts |
TELEMETRY_UI_INTERNAL_HOSTS |
— | Comma-separated hosts that count as your own site, so a self-referral is classified as "Internal" instead of "Referral". Subdomains count. |
host-services |
— | built-ins | The exporter tiles on a host's detail page: each entry is a service name (mysql, redis, postgres, node) with an up metric and the tiles to show, where {host} is substituted with the host being viewed. Add an entry to surface your own exporter. |
The gate
Access is governed by the viewTelemetryUi gate. The default definition
allows access only in the local environment; open it up in your own
AppServiceProvider (app providers boot after the package, so your definition
wins):
Gate::define('viewTelemetryUi', fn ($user) => $user?->isAdmin() ?? false);
The gate also supports per-page restriction and a separate write ability
(manageTelemetryUi) — see authorization.
Query cache & retries
Every panel issues live backend queries each time the SPA fetches it (on load, on a scope change and on each auto-refresh tick).
| Key | Env | Default | Notes |
|---|---|---|---|
cache.ttl |
TELEMETRY_UI_CACHE_TTL |
5 |
Seconds to cache decoded GET responses (plain arrays — never DTOs, so it's safe on any store). Keep it short so data stays fresh; 0 disables. A connection may set its own cache to override. |
retries |
TELEMETRY_UI_RETRIES |
2 |
Retries for a transient connection blip before giving up. |
Backend failures are never cached, and their full detail (URL, response body) is logged server-side while the dashboard shows only a generic message — see connections.
Connections
Named connections to your backends live under connections. The keys
metrics, traces and logs are the defaults; add more named connections and
request them explicitly (e.g. a per-tenant Mimir). Drivers: prometheus /
mimir (metrics), tempo (traces), loki (logs). See
connections and the Grafana proxy
recipe for the full story; the
env-var surface is:
| Connection | URL env | Token env | Tenant env | Extras |
|---|---|---|---|---|
| metrics | TELEMETRY_UI_METRICS_URL |
TELEMETRY_UI_METRICS_TOKEN (falls back to TELEMETRY_UI_TOKEN) |
TELEMETRY_UI_METRICS_TENANT |
TELEMETRY_UI_METRICS_DRIVER, TELEMETRY_UI_METRICS_PREFIX, TELEMETRY_UI_METRICS_BASIC_AUTH, TELEMETRY_UI_METRICS_TIMEOUT |
| traces | TELEMETRY_UI_TEMPO_URL |
TELEMETRY_UI_TEMPO_TOKEN (→ TELEMETRY_UI_TOKEN) |
TELEMETRY_UI_TEMPO_TENANT |
TELEMETRY_UI_TEMPO_BASIC_AUTH, TELEMETRY_UI_TEMPO_TIMEOUT, TELEMETRY_UI_TEMPO_MAX_SEARCH, TELEMETRY_UI_TEMPO_SPANS_PER_TRACE |
| logs | TELEMETRY_UI_LOKI_URL |
TELEMETRY_UI_LOKI_TOKEN (→ TELEMETRY_UI_TOKEN) |
TELEMETRY_UI_LOKI_TENANT |
TELEMETRY_UI_LOKI_BASIC_AUTH, TELEMETRY_UI_LOKI_TIMEOUT |
tenantsets theX-Scope-OrgIDheader (multi-tenant Mimir/Tempo/Loki).tokenbecomes a BearerAuthorizationheader;basic_auth(user:pass) becomes a Basic one. Add arbitrary headers under a connection'sheaders.prefix(metrics) is the API path prefix —mimiris justprometheusunder a prefix (default/prometheus).spans_per_trace(traces, default 100) is how many matching spans a search returns per trace when a panel reads the spans themselves, one row each. Tempo's own default is 3, which cut a request that sent ten mails to three rows.verify(TELEMETRY_UI_METRICS_CA_BUNDLE,_TEMPO_,_LOKI_) points at a CA bundle for a backend behind a private certificate authority. It takes a path; leave it unset to use the system trust store.
Issue tracker (optional)
Setting connections.issues.driver adds an Issues page. Disabled by
default. See issue trackers.
| Key | Env |
|---|---|
connections.issues.driver |
TELEMETRY_UI_ISSUES_DRIVER (github / sentry / linear) |
connections.issues.repo |
TELEMETRY_UI_GITHUB_REPO |
connections.issues.url |
TELEMETRY_UI_ISSUES_URL |
connections.issues.token |
TELEMETRY_UI_ISSUES_TOKEN |
View state
| Key | Env | Default | Notes |
|---|---|---|---|
state.enabled |
TELEMETRY_UI_STATE |
true |
Remember the reader's time window, auto-refresh interval and scope between requests. false restores URL-or-default with nothing carried. |
state.cookie |
TELEMETRY_UI_STATE_COOKIE |
telemetry_ui_view |
Cookie name. Excluded from cookie encryption — the auto-refresh control writes it from the browser. It is a preference, never an authorization input. |
state.lifetime |
TELEMETRY_UI_STATE_LIFETIME |
525600 |
Cookie lifetime in minutes (a year). |
See view state for the precedence rules and the host API.
Discovery caches
| Key | Env | Default | Notes |
|---|---|---|---|
detection.ttl |
TELEMETRY_UI_DETECTION_TTL |
300 |
Seconds to cache the one probe query that decides whether a metric-detected page (e.g. the Statamic page) is visible. |
fleet.ttl |
TELEMETRY_UI_FLEET_TTL |
60 |
Seconds to cache the service/environment list behind the sidebar scope switcher. |
fleet.scopes_logs |
TELEMETRY_UI_FLEET_SCOPES_LOGS |
true |
With "All services" selected, log reads name the services in that list instead of matching any stream. A Loki shared with load balancers, hosts and containers can hold far more than the apps write, and reading all of it for records only the apps emit makes 24-hour log panels time out. When discovery finds no services, logs are read from any stream. The machine logs panel always reads every stream. Set to false to always read every stream. |
Signal context (correlation)
Correlates a trace with the host/runtime signals recorded around it. Full treatment in correlation.
| Key | Env | Default | Notes |
|---|---|---|---|
context.enabled |
TELEMETRY_UI_CONTEXT |
true |
Show the context strip beside the trace waterfall. |
context.window |
TELEMETRY_UI_CONTEXT_WINDOW |
600 |
Seconds padded around a trace so surrounding metric samples land in view. |
context.baseline_window |
TELEMETRY_UI_CONTEXT_BASELINE |
21600 |
Lookback (seconds) for each signal's "typical" value — the number the tile flags against ("95%, typical 30%"). |
context.baseline_ttl |
TELEMETRY_UI_CONTEXT_BASELINE_TTL |
120 |
How long a computed baseline is cached. Baselines are multi-hour averages that barely move, so this is well beyond the live cache and shared across nearby traces. |
context.signals |
— | 5 built-ins | The signal list — each a label / group / unit / PromQL query with a {scope} token (or {host}, {service}, {environment}), and optionally keep_zero. See correlation to add your own. |
hosts.cpu / hosts.memory |
TELEMETRY_UI_HOSTS_CPU / TELEMETRY_UI_HOSTS_MEMORY |
— | PromQL for the Hosts table's CPU and memory columns, one series per host, when the OTel host metrics aren't there (node_exporter). {environment} expands to the viewer's environments for an =~ matcher. |
hosts.host_label |
TELEMETRY_UI_HOSTS_HOST_LABEL |
metrics host label | The label those queries carry the host in (nodename for node_exporter). |
scope.labels.<signal>.<dimension> |
TELEMETRY_UI_METRICS_ENVIRONMENT_LABEL, … |
laravel-telemetry's names | What service, environment and host are called in each backend. See authorization. |
Trace diagnosis
What the trace diagnosis behind the trace_summary, compare_traces and
list_traces MCP tools flags as a
warning.
| Key | Env | Default | Notes |
|---|---|---|---|
traces.diagnostics.slow_query_ms |
TELEMETRY_UI_SLOW_QUERY_MS |
100 |
A query at or over this is a slow query. Keep it at laravel-telemetry's traces.details.slow_span_ms: from 3.5 the root's db.query.slow.count is counted against that, and this is what the per-query flags use. |
traces.diagnostics.overhead_ms |
TELEMETRY_UI_OVERHEAD_MS |
5 |
Telemetry overhead (telemetry.overhead_ms on the root) is flagged from this many ms… |
traces.diagnostics.overhead_ratio |
TELEMETRY_UI_OVERHEAD_RATIO |
0.05 |
…and only when it is also this share of the trace's duration. |
traces.diagnostics.repeat_threshold |
TELEMETRY_UI_REPEAT_THRESHOLD |
3 |
On traces from before laravel-telemetry 3.5 (which marks N+1s itself), a statement that ran this many times is flagged as a repeat. Match the emitter's query_duplicates_threshold. |
traces.waterfall.group_threshold |
TELEMETRY_UI_WATERFALL_GROUP_THRESHOLD |
3 |
How many consecutive identical sibling spans the condensed waterfall folds into one row. Below 2 turns grouping off. See Trace waterfall. |
monitors.enabled |
TELEMETRY_UI_MONITORS |
true |
Offer monitors (laravel-telemetry directives) at all. See Monitors. |
monitors.local |
TELEMETRY_UI_MONITORS_LOCAL |
true |
Monitor this app in-process when it runs the core with directives on. |
monitors.services |
— | [] |
Other apps, keyed by service.name: url, secret (their TELEMETRY_DIRECTIVES_SECRET), optional environment and path. |
monitors.timeout |
TELEMETRY_UI_MONITORS_TIMEOUT |
5 |
Seconds per signed directives call. |
mcp.write |
TELEMETRY_UI_MCP_WRITE |
false |
Register MCP write tools (monitor). |
scope.lock.contexts |
— | null |
Context values a viewer is confined to, e.g. ['tenant.id' => ['7']] (usually from restrictScopeUsing). Governs monitors only. |
MCP server
The local stdio server (php artisan mcp:start telemetry-ui) always works.
The keys below only gate the optional HTTP transport. See the MCP
cookbook.
| Key | Env | Default | Notes |
|---|---|---|---|
mcp.web.enabled |
TELEMETRY_UI_MCP_WEB |
false |
Expose the server over HTTP. |
mcp.web.path |
TELEMETRY_UI_MCP_PATH |
telemetry-ui/mcp |
HTTP endpoint path. |
mcp.web.middleware |
— | ['auth:api', 'throttle:60,1'] |
The only auth on this endpoint (the dashboard gate does not cover it). Keep an auth guard here. |
mcp.web.oauth |
TELEMETRY_UI_MCP_OAUTH |
true |
Register the OAuth 2.1 + Dynamic Client Registration endpoints laravel/mcp provides on top of laravel/passport. If this is true and Passport is not installed, the app throws at boot rather than expose a half-configured authorization server — install Passport, or set this to false and front the endpoint with your own auth middleware. |
Annotations
Point-in-time markers drawn as vertical lines on every chart. Full treatment in the annotations cookbook.
| Key | Env | Default | Notes |
|---|---|---|---|
annotations.enabled |
TELEMETRY_UI_ANNOTATIONS |
true |
Read + draw annotations. |
annotations.ttl |
TELEMETRY_UI_ANNOTATIONS_TTL |
30 |
Seconds to cache the annotation read. |
annotations.markers |
— | 8 built-ins | Map of marker key → { event, label, color, id_label, notes_label }. Each is both read (matched in Loki by event) and written (php artisan telemetry-ui:annotate <key>). Add your own. |
annotations.auto_version.enabled |
TELEMETRY_UI_AUTO_VERSION |
false |
Let telemetry-ui:scan-versions auto-annotate a newly-seen laravel_version. |
annotations.auto_version.metric |
TELEMETRY_UI_AUTO_VERSION_METRIC |
system_cpu_utilization_ratio |
The metric carrying the laravel_version label to scan. |
annotations.auto_version.lookback_days |
TELEMETRY_UI_AUTO_VERSION_LOOKBACK |
30 |
How far back the scan looks for versions. |
Panels
panels is the ordered list of dashboard panels (classes extending
Cbox\TelemetryUi\Panels\Panel). Entries here render first; packages append
their own at runtime with TelemetryUi::panel(MyPanel::class). This key was
cards in 1.x; a leftover cards key is ignored. See pages &
panels.
Live tail
The SSE live-tail endpoint reads two keys, both in the published config and both with env vars: Add them if you need other values:
| Key | Default | Notes |
|---|---|---|
stream.interval |
2 |
Seconds between backend polls on an open stream. |
stream.window |
25 |
Seconds a stream connection lives before it ends and the browser reconnects (resuming from Last-Event-ID). |