feat(browser): Core Web Vitals as browser.web_vital log events - #1150
Conversation
LCP, CLS, INP, FCP and TTFB, reported with the web-vitals library, each
as an OTel log-based event named browser.web_vital with the
browser.web_vital.{name,value,delta,id,rating,navigation_type} attributes
from the browser semantic conventions, plus url.path.
Events, not OTel metrics: a MeterProvider and exporter would add another
SDK to the page and lose the per-page, per-trace detail. Aggregates come
from the warehouse. Each event carries session.id and links to the
document's pageload span, which the deferred chunk now remembers.
The reporter registers before the logs pipeline so vitals reported on page
hide are emitted before its flush listener runs. web-vitals has no
unsubscribe, so it registers once per page and shutdown only gates it.
On by default; webVitals: false turns it off. Lives in the deferred chunk
(deferred budget 8 -> 12 kB); eager is unchanged.
|
Warning Review limit reachedNext included review available in 58 minutes. View limit detailsLimit details: You’ve used all 4 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (12)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Maple reviewConfidence 3/5 · needs attention Adds Core Web Vitals reporting to the browser SDK: LCP, CLS, INP, FCP and TTFB land as
FindingsWarning · F1 ·
|
| Change | Kind | Observable | Evidence |
|---|---|---|---|
Core Web Vitals reporter (startWebVitals) |
log-event emitter to ingest | yes | Emits structured OTLP log events browser.web_vital with semconv attributes, session.id and a pageload trace link (web-vitals.ts:15-29) |
Copy all findings (1)
Findings from an automated review of commit 59c5f2c9174718c577f40455edced4f8c36253d9. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.
---
F1 · Warning · correctness · packages/browser/src/deferred/web-vitals.ts:13-30
`report` drops every web vital while no `pageload` span exists
`if (!pageload) return` keys the whole event on a span that only exists when tracing is live: with `tracing: { enabled: false }`, `setupTracing` never runs, `liveMapleTracer` is undefined and `startNavigation` returns before creating a pageload span (navigation.ts:87), so `webVitals` (default true) emits nothing at all. A vital that settles before the app's first `startNavigation` — TTFB and FCP typically do, the test only passes because it starts the navigation first — is dropped the same way. The doc comment above promises only the trace link is conditional, and `emitLog` already accepts an absent `spanContext`.
Replace those lines with:
function report(metric: Metric): void {
emitLog({
eventName: "browser.web_vital",
severityNumber: Severity.INFO,
severityText: "INFO",
attributes: {
"browser.web_vital.name": metric.name.toLowerCase(),
"browser.web_vital.value": metric.value,
"browser.web_vital.delta": metric.delta,
"browser.web_vital.id": metric.id,
"browser.web_vital.rating": metric.rating,
"browser.web_vital.navigation_type": metric.navigationType,
"url.path": scrubUrl(location.pathname),
},
spanContext: pageload?.(),
})
}
59c5f2c · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple to ask about one.
report() returned early without a pageload span, so vitals were dropped with tracing disabled and before the app's first startNavigation (TTFB and FCP usually settle then). Only the trace link is conditional now.
Maple reviewConfidence 5/5 · safe to merge Adds Core Web Vitals (LCP/CLS/INP/FCP/TTFB) to the browser SDK as
What was checked
|
Maple reviewConfidence 5/5 · safe to merge Adds Core Web Vitals to the browser SDK as
What was checked
Observability coverage: 1 of 1 changes observable
|
Part 4 of the browser SDK stack. Based on #1147.
What changes
web-vitalslibrary (same major asapps/web), each as an OTel log-based event namedbrowser.web_vital, with thebrowser.web_vital.{name,value,delta,id,rating,navigation_type}attributes from the browser semantic conventions, plusurl.path.session.idand links to the document'spageloadspan (the deferred chunk now remembers it when the pageload hook fires).webVitals: falseturns it off.Why events and not OTel metrics
A MeterProvider + metric exporter would add a second SDK to every page and would aggregate away the per-page and per-trace detail that makes a slow LCP debuggable. Percentiles per route come from the warehouse over these events (a rollup is a follow-up on the backend side; until then they are queryable in the logs explorer).
Details worth reviewing
visibilitychangeflush listener runs.web-vitalshas no unsubscribe, so it registers once per page andshutdown()only gates reporting.Testing
init()→ deferred chunk → exporter path: TTFB arrives as abrowser.web_vitalevent with semconv attributes,session.id,url.pathand a pageload trace link.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.