Skip to content

feat(core): Add traceLifecycle option and beforeSendSpan compatibility utilities - #19120

Merged
Lms24 merged 3 commits into
lms/feat-span-firstfrom
lms/span-first-pr2-trace-lifecycle
Feb 4, 2026
Merged

feat(core): Add traceLifecycle option and beforeSendSpan compatibility utilities#19120
Lms24 merged 3 commits into
lms/feat-span-firstfrom
lms/span-first-pr2-trace-lifecycle

Conversation

@Lms24

@Lms24Lms24 commented Feb 2, 2026

Copy link
Copy Markdown
Member

Summary

This PR adds the foundation for span streaming configuration:

  • traceLifecycle option: New option in ClientOptions that controls whether spans are sent statically (when the entire local span tree is complete) or streamed (in batches following interval- and action-based triggers).

Because the span JSON will look different for streamed spans vs. static spans (i.e. our current ones, we also need some helpers for beforeSendSpan where users consume and interact with StreamedSpanJSON:

  • withStreamedSpan() utility: Wrapper function that marks a beforeSendSpan callback as compatible with the streamed span format (StreamedSpanJSON)

  • isStreamedBeforeSendSpanCallback() type guard: Internal utility to check if a callback was wrapped with withStreamedSpan

Usage Example

Sentry.init({traceLifecycle: 'stream',beforeSendSpan: withStreamedSpan((span)=>{// span is of type StreamedSpanJSONreturnspan;}),});

ref #17836

Adds support for span streaming configuration:
- Add `traceLifecycle` option to ClientOptions ('static' | 'stream')
- Add `BeforeSendSpanCallback` type with optional `_streamed` marker
- Add `withStreamedSpan()` utility to wrap callbacks for streamed spans
- Add `isStreamedBeforeSendSpanCallback()` type guard utility
This is part of the span streaming feature that allows spans to be sent
incrementally rather than waiting for the full trace to complete.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actionsBot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊


Generated by Codecov Action

@github-actions

github-actionsBot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser25.43 kBaddedadded
@sentry/browser - with treeshaking flags23.89 kBaddedadded
@sentry/browser (incl. Tracing)42.25 kBaddedadded
@sentry/browser (incl. Tracing, Profiling)46.88 kBaddedadded
@sentry/browser (incl. Tracing, Replay)80.88 kBaddedadded
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags70.48 kBaddedadded
@sentry/browser (incl. Tracing, Replay with Canvas)85.58 kBaddedadded
@sentry/browser (incl. Tracing, Replay, Feedback)97.76 kBaddedadded
@sentry/browser (incl. Feedback)42.15 kBaddedadded
@sentry/browser (incl. sendFeedback)30.11 kBaddedadded
@sentry/browser (incl. FeedbackAsync)35.12 kBaddedadded
@sentry/browser (incl. Metrics)26.55 kBaddedadded
@sentry/browser (incl. Logs)26.7 kBaddedadded
@sentry/browser (incl. Metrics & Logs)27.36 kBaddedadded
@sentry/react27.16 kBaddedadded
@sentry/react (incl. Tracing)44.48 kBaddedadded
@sentry/vue29.88 kBaddedadded
@sentry/vue (incl. Tracing)44.05 kBaddedadded
@sentry/svelte25.45 kBaddedadded
CDN Bundle27.96 kBaddedadded
CDN Bundle (incl. Tracing)43.02 kBaddedadded
CDN Bundle (incl. Logs, Metrics)28.8 kBaddedadded
CDN Bundle (incl. Tracing, Logs, Metrics)43.85 kBaddedadded
CDN Bundle (incl. Replay, Logs, Metrics)67.75 kBaddedadded
CDN Bundle (incl. Tracing, Replay)79.76 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)80.62 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback)85.2 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)86.11 kBaddedadded
CDN Bundle - uncompressed81.78 kBaddedadded
CDN Bundle (incl. Tracing) - uncompressed127.35 kBaddedadded
CDN Bundle (incl. Logs, Metrics) - uncompressed84.61 kBaddedadded
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed130.18 kBaddedadded
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed207.99 kBaddedadded
CDN Bundle (incl. Tracing, Replay) - uncompressed243.95 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed246.77 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed256.75 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed259.56 kBaddedadded
@sentry/nextjs (client)46.85 kBaddedadded
@sentry/sveltekit (client)42.63 kBaddedadded
@sentry/node-core52.17 kBaddedadded
@sentry/node166.22 kBaddedadded
@sentry/node - without tracing93.95 kBaddedadded
@sentry/aws-serverless109.46 kBaddedadded

@github-actions

github-actionsBot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline9,126--added
GET With Sentry1,65918%-added
GET With Sentry (error only)6,12067%-added
POST Baseline1,205--added
POST With Sentry58649%-added
POST With Sentry (error only)1,06388%-added
MYSQL Baseline3,375--added
MYSQL With Sentry49815%-added
MYSQL With Sentry (error only)2,71480%-added

@Lms24Lms24 changed the title feat(core): Add traceLifecycle option and beforeSendSpan utilitiesfeat(core): Add traceLifecycle option and beforeSendSpan compatibility utilitiesFeb 2, 2026
@Lms24Lms24 self-assigned this Feb 2, 2026
@Lms24
Lms24 marked this pull request as ready for review February 2, 2026 16:23

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment threadpackages/core/test/lib/utils/beforeSendSpan.test.ts
* When true, indicates this callback is designed to handle the {@link StreamedSpanJSON} format
* used with `traceLifecycle: 'stream'`. Set this by wrapping your callback with `withStreamedSpan`.
*/
_streamed?: true;

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: As only true is allowed here, we might need to set this type to true | undefined in case someone enabled exactOptionalPropertyTypes.

@Lms24Lms24Feb 3, 2026

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

You're right. However, users shouldn't ever set this but just use the withStreamedSpan helper instead. That being said, it is public API, so we could widen the type enough to make this possible.

Tbh, this withStreamedSpan thing isn't ideal but maybe I could pick your brain a bit for a nicer solution? I was contemplating discrimanted union typing via traceLifecycle but couldn't get it to work without breaking changes for existing users. Maybe you have some ideas how to fix that.

A third option would be to introduce a beforeSendStreamedSpan API for the time span streaming is opt in. Also not ideal because it's again additional API with no great migration path.

Def open for other ideas!

@Lms24Lms24 mentioned this pull request Feb 4, 2026
20 tasks

@JPeer264JPeer264 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.

LGTM

@Lms24
Lms24 merged commit f861ad2 into lms/feat-span-firstFeb 4, 2026
422 of 424 checks passed
@Lms24
Lms24 deleted the lms/span-first-pr2-trace-lifecycle branch February 4, 2026 13:25
@Lms24Lms24 mentioned this pull request Feb 4, 2026
Lms24 added a commit that referenced this pull request Feb 13, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Feb 16, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 2, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 4, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 6, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 9, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 10, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 13, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 18, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
logaretm pushed a commit that referenced this pull request Mar 18, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 23, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Mar 30, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Apr 2, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Apr 8, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Lms24 added a commit that referenced this pull request Apr 9, 2026
…ility utilities (#19120)
This adds the foundation for user-facing span streaming configuration:
- **`traceLifecycle` option**: New option in `ClientOptions` that
controls whether spans are sent statically (when the entire local span
tree is complete) or streamed (in batches following interval- and
action-based triggers).
Because the span JSON will look different for streamed spans vs. static
spans (i.e. our current ones, we also need some helpers for
`beforeSendSpan` where users consume and interact with
`StreamedSpanJSON`:
- **`withStreamedSpan()` utility**: Wrapper function that marks a
`beforeSendSpan` callback as compatible with the streamed span format
(`StreamedSpanJSON`)
- **`isStreamedBeforeSendSpanCallback()` type guard**: Internal utility
to check if a callback was wrapped with `withStreamedSpan`
Sign up for freeto 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.

3 participants

@Lms24@JPeer264@s1gr1d