Skip to content

feat: Span Streaming - #1400

Open
timfish wants to merge 2 commits into
masterfrom
feat/span-streaming-2
Open

feat: Span Streaming#1400
timfish wants to merge 2 commits into
masterfrom
feat/span-streaming-2

Conversation

@timfish

@timfish timfish commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Tests span streaming mode and ensures and startupTracingIntegration works when this mode is enabled.

cursor[bot]

This comment was marked as outdated.

Comment thread src/main/integrations/normalize-paths.ts
@timfish
timfish requested a review from Lms24 July 8, 2026 08:44

@Lms24 Lms24 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks mostly good to me, thanks for taking this on!

Two comments we should address:

  • the timing issue when merging startup and pageload spans
  • do we still need users to set spanStreamingIntegration()?

All other comments are nits/recommendations, so feel free to disregard them/follow-up on in later PRs.

Comment thread src/main/normalize.ts
}

/**
* Normalizes profile_chunk envelope items and returns the modified envelope

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: This just modifies the span envelope, right?

Suggested change
* Normalizes profile_chunk envelope items and returns the modified envelope
* Normalizes span envelope items and returns the modified envelope

Comment thread src/main/normalize.ts

let modifiedEnvelope = createEnvelope(modifiedHeader);
let isSpanContainer = false;
let transactionOrigin: string | undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I'd recommend we rename this to segmentOrigin so that we don't conflate the "new" spans with the old transaction concept. Would also apply to the consumer of this function. Obviously just logaf-l, so feel free to disregard.

// Attributes on the streamed pageload segment that describe the renderer segment itself (its
// identity and SDK metadata) rather than the measurements and trace metadata (Web Vitals,
// connection/device info, etc.) that should be merged onto the startup span.
const NON_INHERITED_SEGMENT_ATTRIBUTES = new Set([

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: We can use @sentry/conventions/attributes to avoid the hard-coded strings and get notified about attribute deprecations. Not directly related to span streaming but IMHO a small win over the hard coded string list here. However, we still need to keep the list itself around so it's not a huge win... feel free to disregard or do as a follow-up. Just a recommendation.

processSpan(span) {
span.name = normalizeUrlToBase(span.name, app.getAppPath());
},
processSegmentSpan(span, client) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of the processSegmentSpan hook here: All spans go through processSpan including segment spans.

debug: true,
tracesSampleRate: 1.0,
traceLifecycle: 'stream',
integrations: [Sentry.spanStreamingIntegration()],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think we don't need to set spanStreamingIntegration() explicitly anymore, right? All clients except for BrowserClient now add the integration, depending on traceLifecycle.

(If you want to keep the test as-is to cover users still explicitly adding spanStreamingIntegration, that's fine, too! no objections!)

* Merges spans streamed from the renderer (when `traceLifecycle: 'stream'` is used) into the
* startup span, mirroring {@link applyRendererSpansAndMeasurements} for the streamed span format.
*/
function applyStreamedRendererSpans(parentSpan: Span, spans: SerializedStreamedSpan[], endTimestamp: number): number {

@Lms24 Lms24 Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m/h: What would happen if the pageload span tree gets sent in multiple envelopes? With streaming we have no guarantee that we wait until the pageload segment span ends. So the browser SDK could send child spans in one envelope, and only later more spans (including the segment) in another. We flush every 5 seconds by default, so this could happen for long-running pageload traces.

IIUC, here we stitch up the pageload segment span and its children into the startup span trace (parentSpan). So previously sent child spans might reference the wrong pageload parent span, since we start a new one here, no?

I might be missing something though that makes this not become an issue 😅. If it is indeed an issue, I wonder if we could buffer incoming span envelopes until we get the pageload segment. Then, we ignore/forward all buffered spans that are not part of the pageload trace as-is, and then merge all pageload-trace spans together before we hand them to applyStreamedRendererSpans. WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants