-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
docs(js): Add Stream Spans guide #17834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 15 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
fac1de3
docs(js): add Node stream spans guide
cleptric d67f9cd
Merge branch 'master' into span-first-js
cleptric 4461c9c
Add srubbing and filtering
cleptric 29765bb
clean up platform include files created for split layout update
inventarSarah 497dc78
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/qu…
inventarSarah c84d25e
finalize split layout include file cleanup
inventarSarah 93fed8f
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/qu…
inventarSarah 6f89d79
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 2d06907
Merge branch 'span-first-js' of github.com:getsentry/sentry-docs into…
inventarSarah f0e25a6
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 9b703d3
create New Spans guide for JS SDKs
inventarSarah 4865de9
update sdk snippets
inventarSarah 31c975c
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 2f89f55
update missing info and fix some snippets
inventarSarah 04a40f8
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 1688a5a
Merge branch 'master' into smi/span-first/js
inventarSarah 653aa8f
fix remix snippet
inventarSarah e3d3699
Merge branch 'smi/span-first/js' of github.com:getsentry/sentry-docs …
inventarSarah 034a6cb
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 0b511d5
describe service spans
inventarSarah b8d6819
add effect and elysia
inventarSarah 0120dc6
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah bd5bdf0
minor fixes
inventarSarah 95337d2
update span names in Drop Spans section
inventarSarah dddd077
Merge branch 'master' of github.com:getsentry/sentry-docs into smi/sp…
inventarSarah 61e9d71
integrate PR feedback
inventarSarah e91978c
verify section update
inventarSarah 2a8fbf1
Update docs/platforms/javascript/common/tracing/new-spans/index.mdx
inventarSarah 93d530f
Apply suggestions from code review
inventarSarah 6bea64c
rename 'New Spans' to 'Streamed Spans'
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
373 changes: 373 additions & 0 deletions
373
docs/platforms/javascript/common/tracing/new-spans/index.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,373 @@ | ||
| --- | ||
| title: New Spans | ||
| description: "Learn how to use stream mode to send spans to Sentry as they finish, removing the 1,000-span limit and making trace data visible sooner." | ||
| sidebar_order: 35 | ||
| new: true | ||
| notSupported: | ||
| - javascript.cordova | ||
| - javascript.effect | ||
| - javascript.elysia | ||
| --- | ||
|
|
||
| <AvailableSince version="10.53.1" /> | ||
|
|
||
| By default, the Sentry JavaScript SDKs collect all spans in memory and send them to Sentry as a single transaction once the root span ends. This is called transaction mode. | ||
| Stream mode changes this by sending spans to Sentry in batches as they finish. | ||
|
|
||
| <Expandable title="Why use stream mode?"> | ||
|
|
||
| - **No 1,000-span limit.** In transaction mode, transactions are capped at 1,000 spans. Stream mode has no upper limit since spans are sent in batches. | ||
| - **Lower memory usage.** Spans are flushed periodically and don't need to be held in memory until the root span ends. This is especially useful for long-running processes like queue consumers or cron jobs. | ||
| - **Faster visibility.** Span data arrives in Sentry as your application runs, instead of only after the entire operation completes. | ||
| - **No data loss from crashes.** If your process terminates unexpectedly, spans that were already flushed are preserved. In transaction mode, a crash before the root span ends means all span data is lost. | ||
|
|
||
| </Expandable> | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| You need: | ||
|
|
||
| - <PlatformLink to="/tracing/#configure">Tracing configured</PlatformLink> in | ||
| your app | ||
| - Sentry SDK `>=10.53.1` | ||
|
|
||
| ## Migrate from Transaction Mode | ||
|
|
||
| For most users, switching to stream mode requires no code changes beyond the initial opt-in. If you use `beforeSendSpan` or `beforeSendTransaction`, follow these steps: | ||
|
|
||
| 1. [Enable stream mode](#enable-stream-mode) | ||
| 2. [Wrap `beforeSendSpan` with `Sentry.withStreamedSpan()` to filter spans](#filter-spans) | ||
| 3. [Replace `beforeSendTransaction` with `ignoreSpans` to drop spans](#drop-spans) | ||
| 4. [Verify the migration](#verify-your-setup) | ||
|
|
||
| ## Enable Stream Mode | ||
|
|
||
| <PlatformContent includePath="performance/enable-stream-mode" /> | ||
|
|
||
| <PlatformSection notSupported={["javascript.nextjs", "javascript.nuxt", "javascript.sveltekit", "javascript.astro", "javascript.solidstart", "javascript.capacitor", "javascript.tanstackstart-react", "javascript.remix", "javascript.react-router"]}> | ||
|
|
||
| <Alert level="success" title="Mixing tracing modes in distributed tracing"> | ||
|
|
||
| Tracing modes are scoped per SDK, which means you can use, for example, stream mode in your frontend, and transaction mode in your backend, or vice versa. | ||
|
|
||
| </Alert> | ||
|
|
||
| </PlatformSection> | ||
|
|
||
| <Expandable title="How does span flushing work?"> | ||
|
|
||
| When stream mode is enabled, the SDK maintains an internal buffer that groups spans by trace ID. | ||
|
|
||
| Spans are flushed: | ||
|
|
||
| - On a regular interval (every 5 seconds by default). | ||
| - When a trace's buffer reaches 1,000 spans. | ||
| - When you call `Sentry.flush()` or `Sentry.close()`. | ||
|
|
||
| Each flush sends only the spans accumulated since the last flush, grouped into envelopes by trace ID. | ||
|
|
||
| </Expandable> | ||
|
|
||
| ## Manual Instrumentation (Optional) | ||
|
|
||
| ### Start a Span | ||
|
|
||
| <SplitLayout> | ||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| Use `Sentry.startSpan()` to create a span that is automatically ended when the callback completes: | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| ```javascript | ||
| const result = await Sentry.startSpan( | ||
| { name: "my-operation", attributes: { "my.attribute": "value" } }, | ||
| async () => { | ||
| // Your code here | ||
| return await doWork(); | ||
| } | ||
| ); | ||
| ``` | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
|
|
||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| Child spans created inside the callback are automatically associated with the parent: | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| ```javascript | ||
| await Sentry.startSpan({ name: "parent-operation" }, async () => { | ||
| await Sentry.startSpan({ name: "child-step-1" }, async () => { | ||
| await stepOne(); | ||
| }); | ||
|
|
||
| await Sentry.startSpan({ name: "child-step-2" }, async () => { | ||
| await stepTwo(); | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
| </SplitLayout> | ||
|
|
||
| For more details on span creation APIs, such as `startSpan`, `startSpanManual`, or `startInactiveSpan`, see <PlatformLink to="/tracing/instrumentation/">Instrumentation</PlatformLink>. | ||
|
|
||
| ### Add Span Attributes | ||
|
|
||
| Attach structured metadata to spans using <PlatformLink to="/configuration/apis/#startSpan">`attributes`</PlatformLink>, which can be `string`, `number`, or `boolean`, as well as arrays of these types. | ||
|
|
||
| <SplitLayout> | ||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| You can set attributes when starting a span: | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| ```javascript | ||
| Sentry.startSpan( | ||
| { | ||
| name: "process-order", | ||
| op: "queue.process", | ||
| attributes: { | ||
| "order.id": "abc-123", | ||
|
inventarSarah marked this conversation as resolved.
Outdated
|
||
| "order.item_count": 5, | ||
| "order.priority": true, | ||
| }, | ||
| }, | ||
| () => { | ||
| // Process the order | ||
| } | ||
| ); | ||
| ``` | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
|
|
||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| Or add them to an already running span: | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| ```javascript | ||
| Sentry.startSpan({ name: "handle-request" }, (span) => { | ||
| // Set a single attribute | ||
| span.setAttribute("http.response.status_code", 200); | ||
|
|
||
| // Set multiple attributes at once | ||
| span.setAttributes({ | ||
| "http.route": "/api/users", | ||
| "user.id": "user-42", | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
|
|
||
| Find more examples in our <PlatformLink to="/tracing/span-metrics/">Sending Span Metrics</PlatformLink> documentation. | ||
|
|
||
| </SplitLayout> | ||
|
|
||
| ## Distributed Tracing (Optional) | ||
|
|
||
| Distributed tracing works out of the box when tracing is enabled and works the same way in stream mode. If you need to manually propagate trace context, for example, | ||
| when the SDK can't instrument automatically, see <PlatformLink to="/tracing/distributed-tracing/custom-instrumentation/">Custom Trace Propagation</PlatformLink>. | ||
|
|
||
| ## Extended Configuration (Optional) | ||
|
|
||
| ### Filter Spans | ||
|
|
||
| <SplitLayout> | ||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| To modify or redact span data before it's sent, use <PlatformLink to="/configuration/options/#beforeSendSpan">`beforeSendSpan`</PlatformLink>. In stream mode, wrap it with `Sentry.withStreamedSpan()` so the SDK applies it to spans as they are flushed rather than only at transaction time. | ||
|
|
||
| <Alert> | ||
| `beforeSendSpan` can only modify span data, and you cannot use it to drop | ||
| spans. Use [`ignoreSpans`](#drop-spans) instead. | ||
| </Alert> | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| <PlatformCategorySection supported={["server", "serverless"]}> | ||
|
|
||
| ```JavaScript | ||
| Sentry.init({ | ||
| dsn: "___PUBLIC_DSN___", | ||
| tracesSampleRate: 1.0, | ||
| traceLifecycle: "stream", | ||
| beforeSendSpan: Sentry.withStreamedSpan((span) => { | ||
| // In stream mode, 'op' is accessed via attributes | ||
| if (span.attributes?.["sentry.op"] === "db.query") { | ||
| // In stream mode, 'description' is now renamed to 'name' | ||
| span.name = "[filtered]"; | ||
| } | ||
| return span; | ||
| }), | ||
| }); | ||
| ``` | ||
|
|
||
| </PlatformCategorySection> | ||
|
|
||
| <PlatformCategorySection supported={["browser"]}> | ||
|
|
||
| <PlatformSection notSupported={["javascript.nextjs", "javascript.nuxt", "javascript.sveltekit", "javascript.astro", "javascript.solidstart", "javascript.capacitor", "javascript.tanstackstart-react", "javascript.remix", "javascript.react-router"]}> | ||
|
|
||
| ```javascript | ||
| Sentry.init({ | ||
| dsn: "___PUBLIC_DSN___", | ||
| tracesSampleRate: 1.0, | ||
| integrations: [ | ||
| // other integrations | ||
| Sentry.spanStreamingIntegration(), | ||
| ], | ||
| beforeSendSpan: Sentry.withStreamedSpan((span) => { | ||
| // In stream mode, 'op' is accessed via attributes | ||
| if (span.attributes?.["sentry.op"] === "db.query") { | ||
| // In stream mode, 'description' is now renamed to 'name' | ||
| span.name = "[filtered]"; | ||
| } | ||
| return span; | ||
| }), | ||
| }); | ||
| ``` | ||
|
|
||
| </PlatformSection> | ||
| </PlatformCategorySection> | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
| </SplitLayout> | ||
|
|
||
| <Alert level="warning" title="Migrating from transaction mode?"> | ||
|
|
||
| If you're using `beforeSendSpan`, wrap it with `Sentry.withStreamedSpan()` as shown above, otherwise the SDK falls back to transaction mode. | ||
| The callback signature and properties of the span object are also shaped differently. See <PlatformLink to="/configuration/options/#beforesendspan">`beforeSendSpan`</PlatformLink> for the full reference. | ||
|
|
||
| If you're using `beforeSendTransaction` to drop spans, use [`ignoreSpans`](#drop-spans) instead, since `beforeSendTransaction` is not available in stream mode. | ||
|
|
||
| </Alert> | ||
|
|
||
| ### Drop Spans | ||
|
|
||
| <SplitLayout> | ||
| <SplitSection> | ||
| <SplitSectionText> | ||
|
|
||
| To prevent specific spans from being created, use the <PlatformLink to="/configuration/options/#ignoreSpans">`ignoreSpans`</PlatformLink> option: | ||
|
|
||
| </SplitSectionText> | ||
| <SplitSectionCode> | ||
|
|
||
| <PlatformCategorySection supported={["server", "serverless"]}> | ||
|
|
||
| ```javascript | ||
| Sentry.init({ | ||
| dsn: "___PUBLIC_DSN___", | ||
| tracesSampleRate: 1.0, | ||
| traceLifecycle: "stream", | ||
| ignoreSpans: [ | ||
| // Drop spans whose name contains "healthcheck" | ||
| "healthcheck", | ||
| // Drop spans whose name matches a pattern | ||
| /^GET \/api\/v1\/internal/, | ||
| // Drop spans matching name and attribute conditions | ||
| { | ||
| name: /^GET \//, | ||
| attributes: { | ||
| "http.response.status_code": 200, | ||
|
Lms24 marked this conversation as resolved.
Outdated
|
||
| "http.route": "/api/status", | ||
| }, | ||
| }, | ||
| ], | ||
| }); | ||
| ``` | ||
|
|
||
| </PlatformCategorySection> | ||
|
|
||
| <PlatformCategorySection supported={["browser"]}> | ||
|
|
||
| <PlatformSection notSupported={["javascript.nextjs", "javascript.nuxt", "javascript.sveltekit", "javascript.astro", "javascript.solidstart", "javascript.capacitor", "javascript.tanstackstart-react", "javascript.remix", "javascript.react-router"]}> | ||
|
|
||
| ```javascript | ||
| Sentry.init({ | ||
| dsn: "___PUBLIC_DSN___", | ||
| tracesSampleRate: 1.0, | ||
| integrations: [ | ||
| // other integrations | ||
| Sentry.spanStreamingIntegration(), | ||
| ], | ||
| ignoreSpans: [ | ||
| // Drop spans whose name contains "healthcheck" | ||
| "healthcheck", | ||
| // Drop spans whose name matches a pattern | ||
| /^GET \/api\/v1\/internal/, | ||
| // Drop spans matching name and attribute conditions | ||
| { | ||
| name: /^GET \//, | ||
| attributes: { | ||
| "http.response.status_code": 200, | ||
|
inventarSarah marked this conversation as resolved.
Outdated
|
||
| "http.route": "/api/status", | ||
| }, | ||
| }, | ||
| ], | ||
| }); | ||
| ``` | ||
|
|
||
| </PlatformSection> | ||
|
|
||
| </PlatformCategorySection> | ||
|
|
||
| </SplitSectionCode> | ||
| </SplitSection> | ||
| </SplitLayout> | ||
|
|
||
| If a matching span is a root span, all of its child spans are dropped as well. If a child span matches, only that span is dropped and its children are reparented to the nearest ancestor. | ||
|
|
||
| In stream mode, `ignoreSpans` is evaluated at span start, so only the span name and attributes available at that point are taken into account. Any name updates or additional attributes added while the span is active won't invluence whether the span is dropped. | ||
|
inventarSarah marked this conversation as resolved.
Outdated
|
||
|
|
||
| <Alert level="warning" title="Migrating from transaction mode?"> | ||
|
|
||
| In transaction mode, `ignoreSpans` is evaluated at root span end rather than at span start. Review your existing rules to make sure the attributes you're matching on are passed when the span is created. | ||
|
|
||
| If you're auto-instrumenting and don't know what the initial name of a span is when it starts, enable SDK debug logging during development by setting <PlatformLink to="/configuration/options/#debug">`debug: true`</PlatformLink> when initializing the SDK. | ||
|
|
||
| </Alert> | ||
|
|
||
| ## Verify Your Setup | ||
|
|
||
| To make sure you've enabled stream mode successfully: | ||
|
|
||
| <PlatformCategorySection supported={["server", "serverless"]}> | ||
|
|
||
| <PlatformSection notSupported={["javascript.nextjs", "javascript.nuxt", "javascript.sveltekit", "javascript.astro", "javascript.solidstart", "javascript.capacitor", "javascript.tanstackstart-react", "javascript.remix", "javascript.react-router"]}> | ||
|
|
||
| - **Check the Sentry dashboard**: Spans should appear in the Traces view shortly after they complete. Traces look the same as in transaction mode, but without transactions. | ||
| - **Check for fallback warnings in your logs**: If the SDK logs warnings about falling back to transaction mode, your `beforeSendSpan` callback is likely missing the `Sentry.withStreamedSpan()` wrapper. | ||
|
|
||
| </PlatformSection> | ||
|
|
||
| </PlatformCategorySection> | ||
|
|
||
| <PlatformCategorySection supported={["browser"]}> | ||
|
|
||
| - **Check the Sentry dashboard**: Spans should appear in the Traces view shortly after they complete. Traces look the same as in transaction mode, but without transactions. | ||
| - **Check for fallback warnings in your logs**: If the SDK logs warnings about falling back to transaction mode, your `beforeSendSpan` callback is likely missing the `Sentry.withStreamedSpan()` wrapper. | ||
| - **Check the network tab in your browser's DevTools**: Span envelopes should appear as individual requests with content type `application/vnd.sentry.items.span.v2+json` | ||
|
|
||
| </PlatformCategorySection> | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.