Skip to content

feat(node)!: Default most SDKs to a no-tracer-provider setup - #22957

Draft
andreiborza wants to merge 14 commits into
developfrom
ab/default-no-tracer-provider
Draft

feat(node)!: Default most SDKs to a no-tracer-provider setup#22957
andreiborza wants to merge 14 commits into
developfrom
ab/default-no-tracer-provider

Conversation

@andreiborza

Copy link
Copy Markdown
Member

What

Flip the default OpenTelemetry setup for server SDKs: most now run without a Sentry tracer provider, using an AsyncLocalStorage context strategy for scope isolation. Controlled by reusing the existing skipOpenTelemetrySetup option, whose default is flipped.

  • Default skipOpenTelemetrySetup to true for @sentry/node (and inheritors: bun, serverless, nuxt, solidstart, astro, remix) and @sentry/cloudflare; no tracer provider is registered.
  • Default it to false for @sentry/nextjs and @sentry/sveltekit, which emit their own OTel spans and need the provider to pick them up.
  • In no-provider mode, install setAsyncLocalStorageAsyncContextStrategy instead of the OTel context strategy. Instrumentation still emits spans via core startSpan; only the OTel provider and propagator are dropped.
  • Stop gating HTTP/fetch span emission on skipOpenTelemetrySetup so auto perf stays on by default.
  • Document the flag, the flipped default, and the spans: false opt-out for bring-your-own-OTel users in MIGRATION.md.

Why

In v11 Sentry no longer takes over your OpenTelemetry setup. Most SDKs do not need a tracer provider to produce spans, so defaulting to none lets users run their own OTel cleanly alongside Sentry without Sentry spans leaking into their pipeline. SDKs that rely on OTel span pickup keep the provider. This also unblocks the light-mode goal from #22418.

Closes: #22486

Flip the default OpenTelemetry setup for server SDKs: most now run without a
Sentry tracer provider, using an AsyncLocalStorage context strategy for scope
isolation. Reuses the existing `skipOpenTelemetrySetup` option with a flipped
default (true for node/cloudflare, false for nextjs/sveltekit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@andreiborza

andreiborza commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

batman begin

…er-provider

# Conflicts:
#	packages/cloudflare/src/sdk.ts
Comment thread packages/node/src/sdk/index.ts
Comment thread packages/node/test/integration/transactions.test.ts
Comment thread packages/node/src/sdk/index.ts
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.91 kB - -
@sentry/browser - with treeshaking flags 28.12 kB - -
@sentry/browser (incl. Tracing) 47.38 kB +0.04% +18 B 🔺
@sentry/browser (incl. Tracing + Span Streaming) 47.38 kB +0.04% +15 B 🔺
@sentry/browser (incl. Tracing, Profiling) 52.15 kB +0.04% +17 B 🔺
@sentry/browser (incl. Tracing, Replay) 86.72 kB +0.03% +19 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 76.15 kB +0.03% +22 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 91.43 kB +0.03% +19 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 104.07 kB +0.03% +21 B 🔺
@sentry/browser (incl. Feedback) 47.22 kB - -
@sentry/browser (incl. sendFeedback) 34.76 kB - -
@sentry/browser (incl. FeedbackAsync) 39.87 kB - -
@sentry/browser (incl. Metrics) 30.99 kB - -
@sentry/browser (incl. Logs) 31.22 kB - -
@sentry/browser (incl. Metrics & Logs) 31.9 kB - -
@sentry/react 31.73 kB - -
@sentry/react (incl. Tracing) 49.65 kB +0.07% +34 B 🔺
@sentry/vue 35 kB +0.06% +20 B 🔺
@sentry/vue (incl. Tracing) 49.37 kB +0.05% +20 B 🔺
@sentry/svelte 29.94 kB - -
CDN Bundle 32.01 kB - -
CDN Bundle (incl. Tracing) 47.75 kB +0.06% +25 B 🔺
CDN Bundle (incl. Logs, Metrics) 33.55 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 49.11 kB +0.06% +26 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 72.9 kB - -
CDN Bundle (incl. Tracing, Replay) 85.38 kB +0.03% +25 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 86.68 kB +0.03% +25 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 91.17 kB +0.04% +30 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 92.48 kB +0.04% +28 B 🔺
CDN Bundle - uncompressed 95.52 kB - -
CDN Bundle (incl. Tracing) - uncompressed 143.18 kB +0.06% +78 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 100.23 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 147.16 kB +0.06% +78 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 224.99 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 262.44 kB +0.03% +78 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 266.4 kB +0.03% +78 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 276.14 kB +0.03% +78 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 280.1 kB +0.03% +78 B 🔺
@sentry/nextjs (client) 52.22 kB +0.03% +13 B 🔺
@sentry/sveltekit (client) 47.82 kB +0.04% +15 B 🔺
@sentry/core/server 80.04 kB +0.04% +29 B 🔺
@sentry/core/browser 52 kB +0.06% +30 B 🔺
@sentry/node 121.18 kB +0.24% +290 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 0 B added added
@sentry/node - without tracing 84.6 kB +0.41% +339 B 🔺
@sentry/aws-serverless 93.25 kB +0.34% +309 B 🔺
@sentry/cloudflare (withSentry) - minified 219.52 kB +0.08% +158 B 🔺
@sentry/cloudflare (withSentry) 540.98 kB +0.1% +505 B 🔺

View base workflow run

In the no-provider default, setupEventContextTrace read the OpenTelemetry active
span before scope data was applied, so a user's own OTel span could override the
Sentry trace on error events. Only set up this hook when Sentry owns the provider.
Assert the actual user-visible effect: a foreign OpenTelemetry active span must
not override the Sentry trace on error events in the no-provider default, and is
adopted when the tracer provider is enabled. Verified to fail without the gating.
Channel-based instrumentation stamps OTel semantic attributes on native spans but
leaves the Sentry-convention fields (e.g. sentry.op) to be inferred by the provider
pipeline. Without a tracer provider that inference never ran, so outgoing http/fetch
and other channel spans were half-formed. Run the same applyOtelSpanData /
backfillStreamedSpanDataFromOtel hooks via the client in no-provider mode.
tracer-start-active-span-error drives the raw OpenTelemetry tracer, and
http-otel-double-instrumentation exercises coexistence with a user-owned OTel
HttpInstrumentation whose spans reach Sentry via the tracer provider. Both require
the provider, so they opt into it explicitly under the new no-provider default.
A trace continued without incoming baggage freezes an empty DSC. Reading it back
short-circuited before sample_rand was added, so downstream requests in no-provider
mode propagated baggage without sentry-sample_rand. Backfill it from the captured
scope's propagation context, matching what the OTel span sampler writes to trace state.
In no-provider mode the AsyncLocalStorage tracing-channel binding planted every
channel span as the active span, including ignored ones. Children and outgoing
requests then propagated from the ignored span, dropping the continued positive
sampling decision. Skip ignored spans so propagation falls back to the nearest
emitted parent, matching the OTel context manager.

@cursor cursor Bot 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.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e7a39a6. Configure here.

Comment thread packages/core/src/asyncContext/tracing-channel-binding.ts
The previous approach backfilled sample_rand in getDynamicSamplingContextFromSpan,
which also ran in OTel mode and wrongly added sample_rand to remote-parent DSCs
(breaking opentelemetry unit tests). Move the backfill to the root-span freeze site
and gate it on a genuinely empty DSC, so only continued traces without incoming
baggage get sample_rand and populated frozen DSCs are left untouched.

Also opt the Cloudflare Vercel AI v6 integration test into the tracer provider: the
AI SDK emits spans via @opentelemetry/api, which need the provider to be captured.
The `otel` transaction context carries the OpenTelemetry SDK resource attributes,
which are only set when Sentry owns the tracer provider. Under the no-provider
default these Astro server SDKs no longer emit it, so the assertion is removed.
The event-loop-block watchdog reads the active scope out of the client's
`asyncLocalStorageLookup`, which was only populated when the OpenTelemetry context
strategy was set up. Without a tracer provider it was undefined, so ANR events fell
back to the global scope and dropped per-isolation-scope user data and breadcrumbs.

Return the AsyncLocalStorage from `setAsyncLocalStorageAsyncContextStrategy` and set
`asyncLocalStorageLookup` in the no-provider branch. The lookup now carries a generic
`stateLookup` key path (empty for the ALS store, which already is the scopes object;
`['_currentContext', ...]` for the OTel context) instead of an OTel-specific symbol.
Continuing a trace without an incoming Sentry DSC now folds the scope's sample_rand
into the propagated (otherwise empty) DSC so downstream sampling stays consistent.
Update the sveltekit handle and browser tracing tests that asserted a strictly empty
DSC in that case.
The server middleware index counter was stored on the OpenTelemetry context, so it
reset to 0 on every middleware under the no-provider default (no context propagation
without a tracer provider), producing indices like [0,0,0]. Key it by the incoming
Request in a WeakMap instead, mirroring the client instrumentation, so it works in
both modes.
Keying the per-request middleware counter by the incoming Request did not increment
in the real server (each middleware hook sees a distinct request object), so indices
stayed [0,0,0]. Key by the request's root span instead, which is the single stable
transaction all of a request's middlewares run under, in both provider modes.
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.

Default most SDKs to a no-tracer-provider setup; opt-in flag to enable it

1 participant