Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Telemetry Ui Laravel Package

cboxdk/laravel-telemetry-ui

View on GitHub
Deep Wiki
Context7
1.4.1

Fixed

  • The TelemetryUi facade's [@method](https://github.com/method) annotation for resolveConnectionsUsing() never gained the needsViewer parameter added in 1.4.0, so a static analyser flagged every correct call as passing an unknown argument. connectionResolverNeedsViewer() is annotated too.
1.4.0

Added

  • Connection probing — Contracts\ProbesConnection. A driver can now answer "is this connection actually usable?" without running a dashboard query, via ConnectionManager::probe($name). The result is a classified ProbeResult (BackendStatus: reachable / TLS / unauthorized / not-found / unexpected-API), because "it didn't work" is useless — a wrong hostname, an untrusted CA, a bad token and a URL pointing at the wrong product need four different fixes. Implemented by the Tempo, Loki, Prometheus and Mimir drivers, each checking the API shape, so a Loki URL pasted into the traces field is caught up front rather than failing on every card. probe() never throws — a malformed config comes back as a failed result.
  • Per-connection TLS options. Connections accept verify: true (default), a path to a custom CA bundle for an internal PKI or self-signed certificate, or false to skip verification. Env keys TELEMETRY_UI_{METRICS,TEMPO,LOKI}_CA_BUNDLE. Only an explicit boolean false disables verification — a stringy "false" from an env var is read as a CA path and fails closed, rather than silently downgrading TLS on a typo.
  • Contracts\WritesToBackend. A marker making the read-only posture checkable instead of claimed: no telemetry read driver implements it, and CreatesIssues now extends it. A host that promises "this never writes to your stores" can assert that, rather than documenting it.
  • resolveConnectionsUsing(..., needsViewer: false). For hosts with no authentication at all, where the connection is a property of the process rather than of a user. The default stays viewer-gated, so existing multi-tenant resolvers — which dereference the user — are never handed null.

Changed

  • SourceException now carries a BackendStatus, classified at the throw site where the HTTP status and transport error are still available, instead of leaving callers to pattern-match on message text.
  • Dropped final from the connector classes per the house rule that package classes stay open to extension (ApiClient, ConnectionManager, ResolvedConnections, SourceException, TempoSource, LokiSource, MimirSource).
1.3.0

Added

  • Statamic pages carry a breakdown, not just a chart. Under each thin overview chart, a list a reader can scan: Static Cache by outcome, Glide by preset, Forms by form, Content by type — which item dominates, without per-item spans. Stache (no facet label to group by) gains a warm-build latency table instead — the p50/p75/p90/p95/p99 distribution behind its single P95 stat.
  • Analytics audience tables now show visitors, not just views. The Campaigns and Sources & audience breakdowns gain a Visitors column beside Views (the distinct-visitor count was already computed but never shown), with a fixed table layout so the compact side-by-side tables can't overflow into each other.

Changed

  • Navigation reorganised. Queues split into their own sidebar group, and Monitoring broken into Frontend (Analytics, Web Vitals, Users) and Infrastructure (Hosts, Logs, System) — so each area is a focused tier-1 entry instead of one long list.

Fixed

  • Chart bars no longer vanish on hover. On the bar charts (e.g. a page's Traffic), ECharts' emphasis state repainted the stacked step-area with a collapsed baseline, so the fill disappeared while the pointer was over it. Emphasis is disabled on the series (the axis tooltip is the hover affordance); annotation markers keep their own emphasis.
  • Detail pages light up the nav again. A hidden detail page (a page, issue, host, request, …) now highlights its list page in both the icon rail and the subnav via a declared parent, instead of leaving the whole navigation with nothing active.
  • Web Vitals aggregate summary restored. The Core Web Vitals card passed its p75 LCP/CLS/INP summary to the stats component under the wrong attribute (:stats instead of :items), so the headline was silently dropped and the page rendered as a bare table.
1.2.0

Changed

  • Require cboxdk/laravel-telemetry ^1.0 (was ^0.3.0). Aligns the dashboard with the now-stable telemetry 1.0 line — the old ^0.3.0 constraint excluded telemetry 0.4 and 1.0, so a fresh install pinned an older telemetry. No dashboard code changes; verified against telemetry 1.0.0 (326 tests green).
1.1.0

A visual overhaul plus New-Relic-style database dashboards. No PHP API changes — the MetricsSource / TracesSource / LogsSource contracts and every result DTO are unchanged from 1.0.0, so drivers built for 1.0 keep working untouched.

Added

  • Query performance dashboards (New-Relic style): DB queries aggregated by normalised statement and ranked by the total DB time they consume (not just the single slowest run), with calls / avg / p95 / max / share, N+1 detection, a per-minute throughput chart, and a query-detail drawer.
  • Searchable comboboxes replace every native <select> (scope, period, auto-refresh, and all per-card filters). Type-ahead filtering, full keyboard navigation (↑/↓/Enter/Esc), and a selected-state check. Each wraps a hidden native <select> so wire:model.live, x-model, and form navigation keep working unchanged.

Changed

  • Full reskin to the Cbox design system: warm-neutral oklch tokens, a light theme by default with a dark toggle (persisted, no flash-of-theme), Plus Jakarta Sans display + JetBrains Mono for data/IDs/numbers, and clear 1px borders. Charts (ECharts) now read the design tokens, so they follow light/dark automatically.
  • Two-tier app shell (Intercom model): a 56px icon rail — three states (minimised / hover-overlay-with-labels / pinned in-flow) — plus a collapsible contextual subnav (header toggle or ⌘.). Both states persist in localStorage.

Notes

  • Cosmetic-only heads-up for downstream customisation: the legacy --tui-* CSS variables are now remapped onto Cbox tokens, and the filter/scope pickers no longer render a visible native <select> (a hidden one is retained for binding). If you overrode --tui-* values or styled those selects directly, review your overrides — no code migration is required.
1.0.0

Backend-neutral query IR — the read side no longer speaks PromQL/TraceQL/LogQL strings directly, which opens the dashboard to non-LGTM backends (see the companion cboxdk/laravel-telemetry-store for a native ClickHouse store).

Changed

  • BREAKING: the MetricsSource / TracesSource / LogsSource contracts now take typed query objects (MetricQuery / TraceQuery / LogQuery) instead of dialect strings. Result DTOs are unchanged. Custom drivers must implement the new signatures — see UPGRADE.md.

Added

  • Queries\Ir\* (query objects, matchers, conditions) and Queries\Compilers\* (Promql/Traceql/Logql compilers). Cards build the IR; each driver compiles it to its dialect. A *::raw() escape hatch covers the few dialect-only cases (nested aggregation, config-driven exporter queries).
  • Everything in 0.4.0 (below) also ships in this release.
0.4.0

Added

  • Scope lock (tenancy). Constrain the whole dashboard to a fixed set of services / environments — dynamically per user via TelemetryUi::restrictScopeUsing(), or statically with no code via telemetry-ui.scope.lock / TELEMETRY_UI_LOCK_SERVICES / TELEMETRY_UI_LOCK_ENVIRONMENTS. The picker now reflects the lock: it offers only allowed values, drops "All" for a locked dimension, and hides a picker locked to a single value entirely. Enforcement stays at query time.
  • Page-detail show pages. Analytics and Frontend rows now open a dedicated page-detail scoped to that one URL path — traffic (views, visitors, referrers, countries, devices), real-user performance (Core Web Vitals + load timings), the page's browser→backend traces, and its browser errors — instead of dumping into a pre-filtered trace search.
  • Richer visitor breakdowns. The analytics "Sources & audience" card gains Sources, Regions, Cities, Operating systems and Browsers alongside Referrers, Countries and Devices, each toggleable via telemetry-ui.analytics.dimensions.
  • Marketing channel — a first-class, zero-cardinality dimension. Visits are classified into Direct / Organic search / Social / Email / Paid / Referral / Internal, derived at read time from the referrer (and UTM medium + paid click-id once the emitter captures them), so it costs no ingest cardinality. Configure your own hosts with telemetry-ui.analytics.internal_hosts.
  • Campaigns card. UTM campaign attribution (campaign / source / medium, and higher-cardinality content / term) from the emitter's telemetry.analytics.utm capture — with a single empty state until it's on.
  • Cardinality guide in the analytics cookbook: per-dimension high/low classification, the capture-vs-surface control split, and the ClickHouse path.

Fixed

  • Chart-annotation toggle no longer shows a duplicate "Cache purge" (the Statamic marker is now its own labelled, distinctly-coloured entry) and its rows/labels align in one clean column.

Changed

  • Requires cboxdk/laravel-telemetry ^0.3.0 for the UTM / campaign capture the Campaigns card and channel enrichment read.
0.3.0

Added

  • Dashboard cards drill into their pages. Cards that summarise a dedicated page (Requests activity/duration, Exceptions, Jobs, queue and autoscale cards) gain a "Requests →"-style header link when rendered on the dashboard or as an embedded widget, carrying the active period/service/env scope. On the card's own page the link is suppressed. Package cards opt in by setting protected ?string $drillPage = 'my-page'.

  • Hide chart annotations per type. The header gains a ⚑ toggle listing the configured marker types (Deploy, Incident, …) with a checkbox each, plus a show/hide-all master switch — uncheck the noisy ones and every chart drops those lines instantly. Purely client-side: cards always ship the full annotation set and the charts filter marker lines by kind, so toggling costs zero backend queries. The choice sits in the URL (ann_off), so it survives navigation and deep links.

  • Grafana-style relative time ranges. ?from=now-1h&to=now, now-7d, now+30m … (units s/m/h/d/w/M/y) work everywhere from/to do — evaluated at view time, so a shared relative link always shows the trailing window instead of a frozen one. Plain unix seconds still work, and the header shows relative expressions verbatim.

  • Livewire updates carry their component everywhere. With cboxdk/laravel-telemetry ≥ 0.2.1, POST /livewire/update is named livewire:{component} (batched updates: livewire:batch), so the routes table groups per component instead of lumping thousands of opaque updates into one row. The request log shows the component(s) behind each update inline, and the Livewire page gains the Requests page's grouping/live-tail pair: a per-component table and a scoped live request log.

  • Collapsible sidebar navigation. The nav groups (Activity, Monitoring, Statamic, …) collapse to chevrons so a long page list fits on one screen; only the active group opens by default and the choice persists in localStorage. Top-level items (Dashboard, Traces, Issues) stay visible.

  • Frontend page rows drill into their traces. Core Web Vitals and Page performance rows open the browser→backend traces for that URL path, matched on span.url.path, carrying the active scope.

Fixed

  • Drill links no longer appear on a card's own page. Cards lazy-load in a follow-up Livewire request where the page route param is gone, so every card thought it was on the dashboard and grew a self-referencing "Autoscale →" link. The page view now passes the page slug into each card at mount.
  • Sparse counters no longer read as zero. Scaling actions and SLA breaches born inside the selected window were invisible to increase() (Prometheus never sees the 0→first-value jump). Cards now count series births too, so "Scale down: 1" shows up the moment the first scale-down ever happens.
  • The Cluster card explains itself on single-host installs instead of showing misleading "0 managers / 0%" stats — the queue_autoscale_cluster_* gauges only exist in cluster mode, and the card now says so.
  • Routes ⇄ Request log toggle no longer reloads the page. The toggle was a plain link (full page load); it is now a Livewire event both sibling cards listen to, so the swap is instant and keeps scroll/filter state.
  • Request log renders full-width. Its live-poll wrapper <div> was the card's grid item, so the span 2 on the inner card never reached the grid and the log was squeezed into one column. The wrapper now uses display: contents.
  • Live tail is on by default on the request log.
  • Scaling actions card matched nothing on real data. The autoscaler's direction label carries up / down (the WorkersScaled action), not scale_up / scale_down; the card now groups by the label instead of filtering on guessed values. Verified against live production series — as are the rest of the autoscale names, including queue_autoscale_sla_breach_ratio and queue_autoscale_sla_predicted_pickup_seconds.
  • Environment scope now works on every log-based card. The scope put deployment_environment_name in the Loki stream selector, but backends that index only service_name as a stream label (e.g. otel-lgtm) carry the environment as structured metadata — so a selected environment silently matched nothing and Analytics, the log viewer, unified errors and annotations all returned zero. The environment is now a pipeline label filter ({service_name="…"} | deployment_environment_name="…"), correct whether the backend indexes it as a stream label or not. The analytics Countries/Devices empty states now name the emitter flags (TELEMETRY_ANALYTICS_GEO / TELEMETRY_ANALYTICS_UA) that populate them.
  • Rootless traces no longer read as a perpetual "Loading…". An orphaned browser page-view trace (no backend root span) showed "Loading…" forever in the drawer; it is now labelled (the span name, "Unnamed trace" or "Trace not found") since the fetch is already complete by render time.
0.2.1

Fixed

  • Queue throughput cards queried queue_metrics_queue_throughput_per_minute; the OTLP collector translates the {jobs}/min unit to a _per_min suffix (verified against live data), so the Throughput card, the queues table's Jobs/min column and the queue-detail header matched nothing. Now they query queue_metrics_queue_throughput_per_min.
0.2.0

Added

  • Queues page (autodetected via queue_metrics_.*) for fleets running cboxdk/laravel-queue-metrics' OpenTelemetry integration: backlog by state (pending/scheduled/reserved), per-queue throughput, oldest-job age, busy/idle worker fleet with utilization, and a per-queue table with backlog-trend sparklines. Each queue drills into a queue-detail page: headline numbers, backlog and throughput for that queue, the autoscaler's target-vs-active steering, and the job classes running on it (each linking on to its job-detail page).
  • Autoscale page (autodetected via queue_autoscale_.*) for cboxdk/laravel-queue-autoscale v3.11+: target vs active workers, executed scaling actions by direction, SLA health (predicted pickup, queues in breach, breach transitions) and cluster capacity (workers/required/capacity, managers, utilization, recommended hosts).

Changed

  • Require cboxdk/laravel-telemetry ^0.2.0 — its first stable release (was ^0.1.0-alpha.3).
0.1.0-alpha.6

Added

  • Copy an issue as Markdown for an LLM. The issue page's Actions & context sidebar gains a ⧉ Copy for LLM button that puts a self-contained Markdown brief on the clipboard — exception, message, location, occurrences/users, environment/release/host, the request that hit it, the suspect change, the releases it rode in on and the freshest stacktrace — ready to paste into a model with "help me fix this". No tracker write access required.

Changed

  • Optional sidebar groups follow the selected service. Schema detection now scopes to the active service/environment, so a group like Statamic (or Horizon, Reverb, …) only appears when that service emits its metrics — not because some other service in the fleet does. "All services" still detects fleet-wide, and the tenancy lock still bounds what a viewer can see.
0.1.0-alpha.5

Added

  • Issue rows go straight to the issue page — no drawer detour — and the page gains a Sentry-style Actions & context sidebar next to the trend: a prefilled "+ Create ticket" button, the tracker tickets that already mention this exception (searched live), the key facts (first/ last seen, users, env, release, host → its page, throw site) and the suspect change event.
  • Request log with live tail. The Requests page's Routes card gains a toggle sibling: a request LOG — individual requests, newest first, with time, method+path, status badge, user, client IP and duration. Filter by user id, client IP, path or status class (each user/IP cell is click-to-tail), hit ● Live and the list re-polls every few seconds — production debugging for "what is this user hitting right now?". Every row opens the readable request story in the pane.
  • Traces read like requests now — the waterfall is the last resort. Opening a trace (pane or full page) tells the story instead of dumping spans: request facts (method, route, path+query, status, client IP, user, user agent, body sizes), cost totals off the root tallies (queries + query time, N+1 count, cache ops, redis commands, models hydrated, views, CPU time, memory), then one readable section per concern — Database (statements slowest-first, N+1 called out), Upstream calls (URL + status + duration), Cache (hit/miss/write summary + keys), Redis, Dispatched jobs, Views, Storage, captured Headers (request/response) and Logs written during the request (trace-correlated). The raw span waterfall collapses behind a "Raw trace — N spans" toggle. Job/command traces adapt automatically.
  • Purpose-built trace filters: status-code class (2xx–5xx), path contains and client IP join status/source/route/name/duration — all URL-synced, all composing scoped TraceQL under the hood.
  • Full issue page (Sentry-style show view). Every error group now has its own page (error-detail?group=…, the drawer's "Full page" button): header with events / users / first seen / last seen, an events trend chart with the deploy/change markers drawn on top (release markers, Sentry-style), tag distributions (host, environment, release, service, user — "is it one box, one release, one customer?"), and the full deep-dive: request strip, root-cause hints, source context, stacktrace and recent occurrences. Drawer and page share one per-request-memoized ErrorGroupReport, so the page's four cards cost one set of backend queries.
  • Users affected. Error groups now count distinct users (from the enduser.id laravel-telemetry ≥ alpha.18 stamps on exception records): a Users column on the errors list and a "users affected" fact on the group panel.
  • Errors list filters. Free-text filter over type/message and a source selector (server / web / full-stack), both URL-synced.
  • Scope moved to the top header. Service and environment now sit next to the period picker on every page — Sentry's top-bar pattern — and the sidebar is pure navigation.
  • Full-color card borders. The context tiles and root-cause box wear their accent color as a full border instead of a left edge.
  • Sentry-style errors list. Every group row now carries its in-period trend sparkline, first seen and last seen, a NEW badge for groups born within 24 hours, and a sort control (events / last seen / first seen). First-seen looks beyond the page period (min 7 days) so it means what it says; counts and trends stay period-scoped.
  • Root-cause hints on the error-group panel. The change event (deploy, migration, feature flag, …) closest before the group's first occurrence — within 48h — is named as the suspect ("Deploy v9.1.0 at 14:02 — first seen 18 minutes later"), and the panel shows which releases the sampled occurrences carry, with an "only this release" badge when every one points at a single release.

Fixed

  • Annotation callout is anchored to its marker line again. The deploy/ change callout now sits hard against the line it describes — flipping to the line's other side near the chart edge (where deploys cluster) instead of detaching to a fixed corner — with a caret pointing back at the line. The raw axis tooltip no longer stacks on top of it: the series readout is suppressed while the callout is open, and the callout renders above it regardless. Hovering into the callout keeps it open to reach Open trace, so the click-to-pin affordance is gone.
0.1.0-alpha.4

Added

  • Error groups live on the Issues page too. The unified Errors card now sits above the tracker list — "what's broken" and "what's filed" on one page.
  • Issue/PR bodies render as formatted markdown. Dependabot's release-notes blocks, headings, lists, code and links display like on the tracker instead of raw tag soup — via a strict-allowlist sanitizer (structural tags only, every attribute dropped except validated http(s) hrefs; scripts/styles/iframes lose their payload entirely), because tracker bodies are external content.
  • Annotations are now interactive. Each chart marker line carries a colored dot handle; hovering it opens a callout ANCHORED to the line (the pointer can move into it), and clicking pins the same callout in the same place — one shape, one position, both triggers. It shows the label, exact time, notes and an "Open trace" button into the emitting trace.
  • Rollout markers cluster. A horizontal deployment emits the same marker from every host within minutes; 200 servers no longer draw 200 lines. Same-kind+label events within a 15-minute gap window fold into one marker showing ×N, the rollout span (first → last host) and the covered hosts — on charts, in the callout and on the Deploys timeline.
  • Host detail page — clicking a host (from the Hosts list or the trace context strip) opens its own page: headline CPU/memory/load/request stats, host-scoped system charts (CPU load, memory, network, filesystem), and a Services on this host card fed by the services' own Prometheus exporters — mysqld_exporter, redis_exporter, postgres_exporter and node_exporter probes ship as defaults, plus an app-side Redis section that needs no exporter at all. Config-driven (telemetry-ui.host-services, {host} token): a probe that returns nothing simply doesn't render, so listing exporters you don't run is free — and adding your own is a config entry, not code.
  • The trace context strip names its scope. The host/runtime tiles now say exactly whose signals they show — the host.name that served the trace (linked to the Hosts page) and the service, or "all hosts" when the resource carries no host and the queries aggregate service-wide. host.name also joined the resource rows in the span attribute panel.
  • Exception groups link back to the request. The error-group panel now shows env / release / host facts off the exception record (host links to its detail page), and a "Latest occurrence" strip off the newest trace root — method + route (linked to the route's detail page), status, user and the request trace. Occurrence rows are whole-row click targets.
  • The drawer is now a docked properties pane on wide screens. At ≥1100px it pushes the page aside instead of covering it — no backdrop, the page stays fully interactive, and selecting another row simply swaps the pane's content (links inside the pane still stack with back-navigation). Narrow screens keep the overlay behavior.
  • "Database (seen by app)" host section — the host page now shows database activity (queries/s, hourly volume, N+1 detections) from laravel-telemetry's new db.queries counter, no exporter required. MySQL/Postgres exporter probes remain the path to real health stats.
  • Host services tell the truth about visibility. App-side sections (like "Redis (seen by app)") carry an observed badge instead of up/down — traffic measured by the app proves usage, not health — plus a note pointing at the exporter that would unlock full monitoring.
  • The drawer opens instantly. Clicking a trace/issue/error row slides the drawer in immediately with a shimmer skeleton; the content morphs in when the backend queries land — no more click lag.

Fixed

  • The route page's Paths card leaked every path in the backend. It used Tempo's tagValues with a filter that v1 quietly ignores — a route detail listed unrelated URLs from the whole fleet. Paths now aggregate from the route's own spans with real numbers per path (requests, avg, max, 4xx/5xx) — a row tails that path in the request log, and ⇄ opens the newest request's story.

  • Charts no longer stick at the width they measured mid-render. The ECharts instance now lives outside Alpine's reactive proxy (a proxied instance silently breaks resize()), and a ResizeObserver keeps the layout in step with the container — Livewire streaming a card in at zero width, sidebar/drawer toggles and orientation changes all heal.

0.1.0-alpha.3

Added

  • Mobile-friendly layout — below 768px the sidebar becomes an off-canvas drawer behind a sticky topbar hamburger, header controls wrap, the trace waterfall drops the per-row service chip so span names stay readable, the custom-range popover anchors to the viewport, the trace drawer goes full-width, and inputs are sized to avoid iOS focus zoom.

  • laravel-telemetry v0.1.0-alpha.16 support — five new auto-detected sidebar pages plus cards, each appearing only when the fleet emits the signals:

    • Horizon (horizon_*): worker processes per supervisor with paused/supervisor gauges, and an incidents chart (long waits, restarts, OOM kills, migrated jobs).
    • Reverb (reverb_*): active WebSocket connections per app with subscribers by channel type and pruned-connection counts, plus message throughput sent vs received.
    • Feature Flags (feature_*, Pennant): checks by flag with active share and per-result badges, and a warning strip for checks against unregistered flags.
    • Storage (storage_operations_*): Flysystem disk operations per minute by type, with per-disk totals.
    • Livewire (livewire_*): mounted vs hydrated components per minute, and a slowest-components table off the render/update/call detail spans.
    • Rate limiting card on the Requests page: 429s per minute by limiter.
    • Core Web Vitals card on the Frontend page: real-user p75 LCP / CLS / INP per path from the SDK's web-vitals spans, toned on Google's thresholds.
    • Duplicate queries (N+1) card on the Queries page, from the db.query.duplicate_detected log events — query text, traces affected, worst repeat count, trace link.
    • CPU profile strip on the trace view: when excimer captured a profile for the trace, the waterfall is headed by top functions by CPU share.
    • Span links (queue retries): linked traces render as clickable rows in a span's attribute panel.
  • Error-group detail drawer (Sentry-style issue view) — clicking a row on the unified Errors card now opens a drawer with the exception's message, occurrence stats (count, first/last seen, source), the latest occurrence's stacktrace and source context, a prefilled "+ ticket" compose button and a recent-occurrences table whose trace links stack onto the drawer. Deep-linkable via ?exception=<group>; searches are forced inside the viewer's tenancy scope lock.

  • Cache purge annotations — two new built-in markers: cache_purge (app-agnostic, emit via php artisan telemetry-ui:annotate cache_purge --id=redis) and statamic_cache_purge, which matches the statamic.cache.purge events cboxdk/statamic-telemetry emits on every stache/static/glide clear — so Statamic purges show up as chart lines and timeline events with no wiring.

  • Issues across multiple reposconnections.issues may now be a list of trackers (frontend, api, sidecar, …), each with a label. The Issues page aggregates them newest-first, tags each row with its repo, and adds a repo filter. A single connection still works unchanged.

  • Manual refresh button in the toolbar, next to the auto-refresh control.

  • Trace list reads like requests — rows now show the HTTP method, route and status (error-highlighted) off the root span, plus a web badge for RUM traces, instead of a bare span name.

  • Row drill-down on Analytics & Frontend — a page row opens every trace for that path, which spans the browser page load and the backend request it triggered (frontend → backend in one waterfall).

Changed

  • Empty states on Analytics/Frontend now hint that the data lives under the app's own service, so an empty page nudges you to check the service scope.

Security

  • Scope lock is now enforced on raw trace queries. A hand-edited or deep-linked ?q= on the Traces page ran verbatim, bypassing the tenancy lock; it is now forced into the viewer's allowed services (drill-down links go through the scoped builder too).
  • Scope lock fails closed. A viewer whose resolver returns an empty allowed set now matches nothing instead of the whole fleet, and deploy-marker queries respect a multi-value lock (previously left unscoped).

Fixed

  • Assets are exempt from the dashboard throttle. The JS/CSS bundle sat behind the same telemetry-ui.throttle (120/min per IP) as the pages, so a busy dashboard — auto-refresh, several tabs, a shared office IP — could 429 the bundle itself and take every chart down (telemetryUiChart is not defined). Version-stamped immutable assets now skip the throttle, the same way they already skip the auth gate.
  • The unified Errors card now works against real data. It searched Tempo for span.exception.group, but laravel-telemetry records backend exceptions as span events (and as structured log records) — the attribute never exists on spans, so the card was permanently empty in production. It now reads the structured exception records from Loki (authoritative — present even when the trace is sampled away) and merges in browser exception spans from Tempo, fingerprinted read-side with the same algorithm the backend uses (browser ingest doesn't stamp exception.group).
  • Deploy-marker annotations are fetched in a single Loki query instead of one per marker type (6+ round trips) — much cheaper on every chart card.
  • TelemetryUi::setCards() / removeCard() now affect the dashboard page's config-declared cards (they previously no-op'd there).
  • A misconfigured repo in a multi-repo connections.issues list is skipped instead of 500-ing the Issues page; a partial per-tracker failure shows a warning banner rather than silently dropping that repo.
  • Per-tenant connection config is keyed safely (no fatal when a resolver returns a closure/resource), memoised per request, and hasIssues() is resolver-aware so page/gate decisions match the tracker actually resolved.
  • The brand accent value can no longer smuggle an external url(...), and an array-shaped ?service[]= no longer corrupts the DashboardViewed audit scope.

Added

  • Integration eventsDashboardViewed (user + page + scope, for audit and usage metering) and BackendQueried (url + method + duration + ok, for backend load metering per tenant) let a host hook the dashboard without patching it.
  • Branding / white-labeltelemetry-ui.brand config sets the sidebar name, logo and accent colour; views are namespaced (telemetry-ui::) so a host can override any of them.
  • Per-tenant backendsTelemetryUi::resolveConnectionsUsing(fn ($user) => [...]) resolves connection config per viewer, so a hosted multi-tenant install can point each tenant at their own Mimir/Tempo/Loki (or a shared backend behind a per-tenant X-Scope-OrgID). Omitted connections fall back to the static config; drivers are cached by config, so one tenant never gets another's under Octane. See authorization.
  • Tenancy scope lockTelemetryUi::restrictScopeUsing(fn ($user) => [...]) locks a viewer to a subset of services and/or environments, for embedding the dashboard in an app. The scope switcher only offers the allowed values and every query is forced into the lock server-side — a blank or hand-edited ?service= can't widen past it (one allowed service → service_name="x", several → a service_name=~"a|b" alternation), across metrics, traces and logs. Resolved per request. See the authorization doc.
0.1.0-alpha.2

Added

  • Analytics page (visit analytics) — a privacy-first traffic dashboard built on the emitter's unsampled analytics.page_view stream: a page-views trend chart (with deploy annotations), unique visitors (the cookieless daily session hash — no cookies, no stored IP), views-per-visit, bounce rate (single-page-view sessions) and average engagement time (from analytics.engagement events), top pages with distinct visitors, and a sources/audience breakdown (referrers, and — when the emitter's geo/User-Agent enrichment is on — countries and devices). Trace/Loki-sourced so it's exact for low-traffic sites and a bounded sample at scale (the eventual answer being a ClickHouse sink behind the same cards). Also: the Loki driver now surfaces per-entry structured metadata, so high-cardinality OTLP log attributes (the visit dimensions) are readable instead of dropped.

  • Frontend page (RUM) — a new Monitoring page for real-user browser data: Page performance (navigation timings per page — loads, avg load, TTFB, DOM-interactive, from the document.load spans) and Failed browser requests (fetch/XHR calls that 5xx'd or errored, grouped by URL, each row opening a representative trace where a same-origin failure continues into the backend span that caused it). Trace-sourced (no RUM metric exists), bounded sample.

  • Unified errors list (frontend + backend) — a new lead card on the Exceptions page groups every error by exception.group, the Sentry-style fingerprint (class + top in-app frame) that both the backend handler and the browser SDK stamp with the same algorithm. A JS TypeError and a PHP exception that are "the same issue" collapse into one row tagged web/server/full-stack, with an occurrence count and last-seen; clicking a row opens a representative trace (→ waterfall + host context), and "all" jumps to every trace for that fingerprint. Trace-sourced (metrics can't unify — frontend errors exist only as spans), so counts are over a bounded recent sample.

  • Frontend / RUM spans in the unified trace — browser spans emitted by cboxdk/laravel-telemetry's frontend proxy (alpha.6/7) now read as first-class frontend rows. They share the backend's service.name, so the per-span server-stamped browser=true attribute is the marker: browser spans get a web badge in the waterfall, document.load shows its RUM timings (TTFB, DOM), and browser fetch spans render their URL + status. Trace search gains a Source filter (frontend/backend) that scopes on span.browser. Because the browser continues the backend's traceparent, a page load, its fetches and the server spans they trigger already nest into one waterfall — end-to-end frontend→backend on open data.

  • Dimensional drill-down / filtering (Grafana-style) — every span/resource attribute in the trace properties window (host, user, team, client IP, deployment, method — whatever the app emits) is a click-to-filter link that scopes Traces to { .key = "value" }. Plus a new Hosts page listing every host/server reporting telemetry (request volume, errors, CPU, memory), each row filtering requests to that host.

  • Purpose-built detail pages with progressive drill-down — clicking a row opens a dedicated detail page instead of a pre-filtered trace search, à la Nightwatch, for routes, jobs and exceptions. Each shows the entity's own numbers scoped to it, and drills deeper: a route detail goes throughput → latency → exact status codes → its individual traces (→ waterfall + host context). Built on a "hidden page" concept (routable + rendered, out of the sidebar), a scopeMatchers() card hook and per-entity ScopesTo* traits, so the overview cards are reused scoped to one entity — the pattern extends to hosts, queries, etc. cheaply.

  • MCP serverphp artisan mcp:start telemetry-ui serves metrics, traces, logs and the correlation/analysis tools over the Model Context Protocol, built on the first-party laravel/mcp package, so an agent (Claude Desktop, Cursor, …) can query the stack directly for incident RCA. Six read-only Server\Tools, including trace_context (a trace plus the host/runtime signals around it, flagged against normal). Same read drivers the dashboard uses.

  • Remote MCP over HTTP with OAuth + DCR — set TELEMETRY_UI_MCP_WEB=true (and install laravel/passport) to expose the server over HTTP behind auth:api, with the OAuth 2.1 authorization server and Dynamic Client Registration endpoint that laravel/mcp provides — no custom OAuth code. Off by default; Passport stays optional.

  • Signal correlation — a trace now shows the host and runtime signals recorded around it (CPU, load, memory, network, process RSS) in a context strip beside the waterfall, scoped by service + host and the trace's time window. This is the thing an app-only monitor can't do: the same Prometheus scrapes system_*/process_* — and node_exporter, mysqld_exporter, … when present — right next to the app. Config-driven and fail-open per signal (telemetry-ui.context.signals); a new headless Analysis\SignalContext is the reusable foundation.

  • "What was different" — each context signal also carries its baseline (the typical value for that scope over a longer lookback), so a tile reads "Host CPU 95% (typical 30%)" and flags outliers. Answers the "was the box busted?" question at a glance, without ML — just an honest comparison to normal.

  • php artisan telemetry-ui:check — probes each configured connection with its cheapest read and reports OK/FAIL/not-configured; exits non-zero on failure so it doubles as a deploy healthcheck.

  • Annotation writingphp artisan telemetry-ui:annotate <marker> emits a marker (deploy, incident, scaling, migration, feature, version — or your own) through the telemetry pipeline into Loki, where it renders as a vertical line on every chart. No local state: the same store the dashboard already reads. cboxdk/laravel-telemetry is now a hard dependency (it provides the write path, and the dashboard instruments its own stack).

  • Proactive auto-version annotationsphp artisan telemetry-ui:scan-versions (schedule it) detects a laravel_version that's live in the metrics but un-annotated and marks it, so an un-announced deploy still lands on the charts. Stateless: it dedups against the version annotations already in Loki.

  • Whole-row click targets on the routes, jobs, facet, slow-query, trace-search, outgoing and exceptions tables — the entire row drills into the matching traces (or opens the trace drawer / matching issues), not just the small link. cmd/ctrl-click opens in a new tab. Outgoing rows filter traces by server.address; exception rows jump to their matching issues (or the scoped error traces when no tracker is configured).

Changed

  • Dashboard cards now stream in (lazy on-load) instead of rendering eagerly, so the page shell paints instantly and a slow backend query on one card no longer blocks the whole page; each card loads in its own parallel request.

Fixed

  • Chart hover tooltips and drag-to-zoom both work now. The dataZoom brush was kept permanently armed for drag-select, which put every chart in select-mode and suppressed hover tooltips — so "no data on hover" and "zoom broken" were the same bug. Replaced with a raw zrender drag-select (own selection band), so hovering shows values (trigger: 'axis') and dragging realigns the range.
  • Linear now surfaces GraphQL errors (auth/permission/query failures, which Linear returns as HTTP 200 with an errors array) as a SourceException instead of silently returning an empty issue list.
  • Prometheus/Mimir non-finite values: NaN/+Inf/-Inf (which Prometheus serializes as strings) were cast to a misleading 0.0. They are now dropped so gauges/ratios show a gap instead of a false zero, and the scalar result branch no longer risks a raw TypeError past the SourceException boundary.
  • Fleet (sidebar service/environment) cache TTL is now config-wired (telemetry-ui.fleet.ttl / TELEMETRY_UI_FLEET_TTL), matching the other cache TTLs.

Changed

  • ConnectionManager::client() is now public so custom drivers registered via extend() can reuse the configured ApiClient (auth, tenancy, cache, retries) instead of building one by hand.

Security

  • Finer-grained authorization. The viewTelemetryUi gate is now re-run on Livewire updates (card/drawer actions POST to /livewire/update, which previously skipped it — the gate was only enforced at page load). The gate also receives the page slug, so an app can restrict individual pages (e.g. the PII-heavy Logs/Users) without closing the whole dashboard — denied pages 403 and drop from the sidebar/palette. And a new manageTelemetryUi ability gates write actions (creating tracker issues), checked server-side and hiding the compose UI, so a read-only viewer can't file tickets (it falls back to the view gate, so existing setups are unchanged). See the new authorization doc.
  • Backend failures no longer leak the internal endpoint, query string or raw response body to the dashboard. SourceException now carries a generic user-facing message and a separate detail; ApiClient logs the full detail server-side (the dashboard gate may be opened to semi-trusted operators).
  • The MCP web transport throws at boot when OAuth is enabled but laravel/passport is absent, instead of registering a half-configured authorization server. mcp.web.middleware documents that auth:api is the only guard on that endpoint.
  • MCP tools are bounded (row/series/window/limit caps + a dedicated throttle), tagValues lookups carry a time window + limit, and the annotation writer can no longer crash a command or the scan-versions cron on an emit failure.

Documentation

Verified

  • GitHub and Linear issue read and create paths exercised end-to-end against the live APIs. Sentry remains fixture-tested only — see the verification-status table in the issue-trackers docs.
0.1.0-alpha.1

First alpha. A Livewire + ECharts observability dashboard querying Tempo (TraceQL), Loki (LogQL) and Prometheus/Mimir (PromQL) directly — a companion to cboxdk/laravel-telemetry.

Added

  • Connector layer with MetricsSource/TracesSource/LogsSource/IssuesSource contracts and Prometheus, Mimir, Tempo, Loki, GitHub, Sentry and Linear drivers, resolved lazily through a ConnectionManager with extend().
  • Full Nightwatch-inspired information architecture: dashboard, requests, jobs, commands, schedule, exceptions, queries, cache, outgoing, mail, users, logs, system and traces pages, with a service/environment scope switcher.
  • Trace waterfall with infra-chain nesting, drag-to-zoom charts that adapt sampling, Loki-backed deploy annotations, facet views, sparklines, a command palette and stacked slide-in drawers.
  • Issue trackers as a fourth signal, with create-a-ticket-from-an-exception for GitHub and Linear.
  • Schema autodetection (e.g. the built-in Statamic page) via metric presence.
  • Short-TTL query cache: decoded backend GET responses are cached for telemetry-ui.cache.ttl seconds (default 5, override per connection) so a busy dashboard with many cards and auto-refresh does not hammer Prometheus/Tempo/Loki. Only plain arrays are cached, never DTOs.
  • Transient-blip retry on backend connections (telemetry-ui.retries).
  • Rate limiting on the dashboard routes via telemetry-ui.throttle (default 120,1).
  • CI: run-tests (PHP 8.3–8.5 × Laravel 12/13, lowest/stable), PHPStan level 8 and Pint workflows.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle