From 342e1892441edcc6116034309fa4839ba148ccf5 Mon Sep 17 00:00:00 2001 From: dev Date: Fri, 24 Apr 2026 04:29:25 +0200 Subject: [PATCH] Document two Sentry paths for Web Vitals; enable browserTracing in test page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - logr README: restructure the Vitals + Sentry section into two clearly separated delivery paths. Path A (via the logger → sentryTransport) reaches Issues/breadcrumbs; Path B (via Sentry's browserTracingIntegration) reaches the Performance/Insights product. Add a decision table covering the five common use cases (aggregate dashboards, triage breadcrumbs, alerts on poor ratings, non-Sentry backends, dev validation) with the recommended path for each, and document the production combo of Path B for analytics plus Path A at `breadcrumbLevel: TRACE` for error-context breadcrumbs. - Test page: enable Sentry.browserTracingIntegration() with tracesSampleRate=1.0 so the page load emits a real transaction visible under Insights → Browser → Web Vitals, in addition to the logger-based vitals that already land as Issues. Promote every vital rating to ERROR in the test page override so good/needs-improvement samples also surface in the Issues feed — useful to validate end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/arts/logr/README.md | 86 +++++++++++++++++++++++++++ src/web/routes/test/logr/+page.svelte | 19 +++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/arts/logr/README.md b/src/arts/logr/README.md index b391ee0..db29f42 100644 --- a/src/arts/logr/README.md +++ b/src/arts/logr/README.md @@ -464,6 +464,92 @@ query directly in your observability backend: - **Sentry discover:** group events by `tag.category = vitals` and `tag.tag:lcp`, plot p75 per release - **Datadog logs:** facet on `metric` and `route`, dashboard p95/p99 per route +### Vitals + Sentry: two delivery paths + +Vitals can reach Sentry through **two independent pipelines**, each feeding +a different Sentry product. Knowing which is which avoids noise and gives +you the right dashboard for the question you're asking. + +#### Path A — through the logger (what `registerWebVitals` does) + +Vitals flow as regular `LogEntry` objects through every transport, including +`sentryTransport`. They end up as **Sentry Issues** (if promoted to ERROR) +or **breadcrumbs** (at INFO/WARN), alongside your normal logs. + +| Rating | Default level | Reaches Sentry as … | +| ------------------ | ------------- | ------------------------------------------------------------------ | +| `good` | DEBUG | Dropped (below `breadcrumbLevel: INFO`) | +| `needs-improvement`| INFO | Breadcrumb (attached to the next captured event, not a new Issue) | +| `poor` | WARN | Breadcrumb (still below `eventLevel: ERROR`) | + +With the defaults, vitals rarely appear as Sentry **Issues** — **this is by +design**. In production you do not want every page load producing an Issue. + +**Best production use of Path A:** lower `breadcrumbLevel` so vitals become +rich context on the next captured error, without flooding the Issues feed: + +```ts +logger.addTransport(sentryTransport(Sentry, { + eventLevel: LogLevel.ERROR, + breadcrumbLevel: LogLevel.TRACE // every sample becomes a breadcrumb +})); +``` + +**Validation trick for dev pages** — temporarily promote every sample to +ERROR so they show up as Issues and you can confirm the pipeline: + +```ts +registerWebVitals(logger, webVitals, { + levels: { + good: LogLevel.ERROR, + 'needs-improvement': LogLevel.ERROR, + poor: LogLevel.ERROR + } +}); +``` + +#### Path B — through Sentry's native Browser Tracing (recommended for production) + +Sentry's own `browserTracingIntegration` auto-captures Web Vitals and emits +them as **Performance transactions**. These land in a dedicated product and +do not pollute the Issues feed. + +Where to find them in the Sentry dashboard: +- **Insights → Browser → Web Vitals** — aggregate p75/p95 per route, browser, + device, release +- **Performance → Transactions** — per-pageload detail with full vitals, + resource timing and long tasks + +Setup (this is a one-time thing at app init, nothing to do in `logr`): + +```ts +import * as Sentry from '@sentry/browser'; + +Sentry.init({ + dsn: '', + integrations: [Sentry.browserTracingIntegration()], + tracesSampleRate: 0.1 // 10% of page loads send a transaction +}); +``` + +Vitals now flow automatically — no call to `registerWebVitals` needed for +this path. + +#### When to use which + +| Use case | Path | +| ----------------------------------------------------------- | ---- | +| Aggregate dashboards (p75 LCP by route, regressions by release) | **B** (Sentry Performance) | +| Correlate vitals with a specific error (debugging triage) | **A** at `breadcrumbLevel: TRACE` (breadcrumbs on error events) | +| Alerts on poor ratings (`poor` LCP → PagerDuty) | **A** with `poor: LogLevel.ERROR` + Sentry Alert rule on the tag | +| Ship vitals to **non-Sentry** backends (Loki, Datadog, OTel) | **A** — the logger fans out to every transport | +| Validate the pipeline during development | **A** with all ratings at ERROR (noisy but visible in Issues) | + +The two paths are complementary and can run in parallel. In production the +common setup is **Path B for analytics + Path A as breadcrumbs** — you get +the aggregate view under Performance and contextual vitals on every error, +without a single extra Issue. + --- ## Patterns diff --git a/src/web/routes/test/logr/+page.svelte b/src/web/routes/test/logr/+page.svelte index 98aac1b..3952600 100644 --- a/src/web/routes/test/logr/+page.svelte +++ b/src/web/routes/test/logr/+page.svelte @@ -196,8 +196,16 @@ registerWebVitals(logger, webVitals, { // Custom tag so we can filter this page's vitals easily in dashboards. tags: ['test-page'], - // Promote 'poor' to ERROR to stand out visually in the table. - levels: { poor: LogLevel.ERROR } + // In this test page we promote every rating to ERROR so Sentry shows + // them as Issues — useful to validate the pipeline reaches the + // dashboard. In production you would keep the defaults (good=DEBUG, + // needs-improvement=INFO, poor=WARN) and route vitals through + // breadcrumbs or a metrics sink, not as individual Issues. + levels: { + good: LogLevel.ERROR, + 'needs-improvement': LogLevel.ERROR, + poor: LogLevel.ERROR + } }); vitalsEnabled = true; } @@ -231,7 +239,12 @@ environment: 'logr-test', release: 'logr-test@1.0.0', sampleRate: 1.0, - tracesSampleRate: 0 + // Browser tracing captures native Web Vitals (LCP/INP/CLS/FCP/TTFB) + // and sends them as Performance data — visible under + // "Insights → Browser → Web Vitals" in the Sentry dashboard. + integrations: [Sentry.browserTracingIntegration()], + // 1.0 = every page load sends a transaction; lower it in production. + tracesSampleRate: 1.0 }); persistDsn(); sentryStatus = 'ready';