feat(browser): XHR spans and page load timing - #1147
Conversation
- XMLHttpRequest is instrumented like fetch (tracing.instrumentXhr, default true), with the same ingest ignore list, traceparent CORS allowlist, URL redaction and pagehide end for spans still waiting on resource timing. axios and older clients no longer drop out of the browser -> backend trace. - An export-time HTTP status policy gives fetch and XHR one rule: a response status alone never makes a client span Error. The XHR instrumentation marks every status >= 400 Error, and every Error span becomes an issue, so without this each 404 would have opened one. Network failures and recorded exceptions are kept. - The replay network capture now opens its trace-id slot around XHR open() too, since the XHR instrumentation starts its span there; replay network rows for XHRs link to their traces again. - The document's pageload span starts at navigation start, and gets child spans from the Navigation Timing entry: documentFetch (with dns, connect, request, response), domProcessing and loadEvent. They are recorded in the deferred chunk, handed the pageload span through a small hook. - Eager budget 42 -> 43 kB for the XHR instrumentation and status policy.
|
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 (17)
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 Warning This review ended early; what follows is what it established. Adds XHR auto-instrumentation (new
FindingsWarning · F1 ·
|
| Change | Kind | Observable | Evidence |
|---|---|---|---|
XHR client spans via XMLHttpRequestInstrumentation |
client | yes | OTel instrumentation registered with the explicit provider (tracing.ts:260) |
document load timing spans (documentFetch, phases) |
internal/client | yes | started on Maple's tracer under the pageload span (deferred/document-timing.ts:44-62) |
| HTTP status policy on exported client spans | span processing | yes | HttpStatusExporter wrapped inside ConsentSpanExporter (tracing.ts:168) |
Copy all findings (1)
Findings from an automated review of commit 469db42d5e17941658d16bb8c12d9e1f5e1dda3a. 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/navigation.ts:91-92
`pageload` at `performance.timeOrigin` is filtered out by the consent start-time check
`ConsentSpanExporter.export` keeps only spans whose `startTime` is at or after `consentAllowedSince()` (tracing.ts:81). Starting the first `pageload` span at `performance.timeOrigin` gives it a start time before any consent granted during that page load, so the span is dropped at flush and the first page load loses its root trace — the document timing and loader spans it parents then export as an orphaned trace. Confirm against `consentAllowedSince` and, if it is the grant time, clamp the start time to the consent grant (or exempt `pageload` from the filter).
469db42 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple to ask about one.
With privacy.requireConsent, consent granted during the page load made the pageload span (started at navigation start) begin before the grant, and the consent exporter dropped it. It now starts at the later of the two.
Maple reviewConfidence 3/5 · needs attention Adds XHR auto-instrumentation (default on), an exporter that clears status-only client Errors so 404s open no issue, a replay trace-id fix for spans started in
FindingsWarning · F2 · Status policy clears Error on 5xx client spans too, not just 4xxcorrectness ·
What was checked
Observability coverage: 2 of 2 changes observable
Copy all findings (1)
|
Maple reviewConfidence 3/5 · needs attention Adds XHR auto-instrumentation with a shared HTTP status policy, a replay trace-id link for XHR, and Navigation-Timing child spans under
Still open from earlier reviews
What was checked
Observability coverage: 2 of 2 changes observable
|
Part 3 of the browser SDK stack. Based on the error filters PR.
What changes
XHR spans (
tracing.instrumentXhr, default true)@opentelemetry/instrumentation-xml-http-request, configured like fetch: ingest calls ignored,traceparentonly to same-origin orpropagateTraceHeaderCorsUrls, URLs redacted, and spans still waiting on resource timing ended onpagehide.One HTTP status rule for fetch and XHR
Error, and every Error span becomes an issue inerror_events_mv, so enabling it as-is would have opened an issue for every 404.HttpStatusExporterclears an Error that was set only because of the response status (client span, numericerror.type, no exception event). Network failures and recorded exceptions keep their Error. The status can't be reset in the instrumentation hook, sincesetStatus(Unset)is a no-op in the SDK.errors.captureHttpStatus).Replay link fix
open(), but the replay network capture only opened its trace-id slot aroundsend(), so XHR rows in the session transcript would not link to their trace. It now opens one aroundopen()as well (packages/browser-session, also used by the Effect SDK; the change is generic).Page load timing
pageloadspan now starts at navigation start (performance.timeOrigin), not when the app's JS reachedstartNavigation.documentFetch(withdns,connect,request,responseunder it, span names matching the upstream document-load instrumentation),domProcessingandloadEvent. Phases that didn't happen are skipped.Eager budget 42 → 43 kB for the XHR instrumentation and status policy, which must patch before the app's first request.
Testing
HttpStatusExporterunit tests (status-only Error cleared; network failure, recorded exception and non-client spans kept).pagehide; the replay capture linking an XHR to a span its tracer started inopen()(fails without the fix); document timing parented and timed against the real navigation entry, and not repeated for later navigations.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.