feat(browser): request/response headers on spans, replay bodies and canvas - #1157
Confidence 3/5 · 1 issue to address
Confidence 3/5 · needs attention
The body-capture path changes when a replay network event is emitted; everything else is additive and covered by tests.
quality 90/100 · 1 warning · tests covered · risk medium · 1/2 new units observable
Adds allowlisted fetch/XHR headers as HTTP semconv span attributes, optional text bodies on replay network events, and opt-in rrweb canvas capture. Safe to merge apart from the deferred network event on streamed responses.
tracing.captureHeaderssetshttp.request.header.*/http.response.header.*on fetch and XHR spansreplay.networkBodieskeeps cut text bodies on matched replay network eventsreplay.canvasFpsrecords WebP canvas frames in both recordersnetworkBodies.maxLengthdefaults to and is capped at 1,000
Findings
Warning · F6 · Fetch network event is deferred to the body read, so a streamed response records none
correctness · packages/browser-session/src/replay/capture/network.ts:61-78
When networkBodies matches the URL, record runs only inside the .then after readPrefix, which loops until the accumulated text exceeds maxLength (1,000 by default) and awaits reader.read() in between (network.ts:157). A text/event-stream or long-poll response that stays open without delivering 1,000 characters never resolves the read, so the request never appears in the replay network panel at all — before this change the event was recorded as soon as the fetch settled. TEXT_CONTENT matches text/event-stream because of its text/ prefix.
Emit the network event as soon as the response settles and attach the bodies only to the read that has finished, or exclude `text/event-stream` from `TEXT_CONTENT` so streams take the plain path.
Fixed since the last review
F5 · AgRegExp innetworkBodies.urlsmatches only every other request
What was checked
- F5 fixed:
matchesUrlresetslastIndexbeforepattern.test(network.ts:12), global regex matches every request - Credential headers removed and names lowercased at config time (http-headers.ts:17), never reaching a span
- Body reads are bounded by
maxLengthand the clone reader is cancelled (network.ts:157-163)
Observability coverage: 1 of 2 changes observable
| Change | Kind | Observable | Evidence |
|---|---|---|---|
| fetch/XHR span header attributes | outbound call | yes | http.request.header.* / http.response.header.* set on the existing instrumentation spans (tracing.ts:267-290) |
| replay request/response body capture | background read in the browser | no | bodies ride on session events as request.body/response.body (network.ts:35-36); no span is expected in a replay engine |
a38cd6e · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple to ask about one.
Annotations
Check warning on line 78 in packages/browser-session/src/replay/capture/network.ts
maple-review-bot / Maple / review
correctness: Fetch network event is deferred to the body read, so a streamed response records none
When `networkBodies` matches the URL, `record` runs only inside the `.then` after `readPrefix`, which loops until the accumulated text exceeds `maxLength` (1,000 by default) and awaits `reader.read()` in between (network.ts:157). A `text/event-stream` or long-poll response that stays open without delivering 1,000 characters never resolves the read, so the request never appears in the replay network panel at all — before this change the event was recorded as soon as the fetch settled. `TEXT_CONTENT` matches `text/event-stream` because of its `text/` prefix.