ref(node): Fold breadcrumb & trace propagation into node fetch instrumentation#21872
Conversation
…instrumentation Enhance the node `undici-instrumentation` so it is a single instrumentation that emits `http.client` spans (gated by a `spans` option, default `true`), records breadcrumbs, and propagates traces for outgoing fetch/undici requests. This replaces the previous setup where span creation (`instrumentUndici`) and breadcrumb/trace-propagation (`SentryNodeFetchInstrumentation`) ran as two separate subscribers on the same diagnostics channels. Trace propagation now goes through the dedup-aware `addTracePropagationHeadersToFetchRequest`, which gained an optional `span` argument so the outgoing headers reference the `http.client` span while still de-duplicating against any trace headers the user set manually (e.g. via `getTraceData()`). This keeps the change contained to the `node` package to ease review; a follow-up moves the instrumentation into `node-core`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
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.
Reviewed by Cursor Bugbot for commit d43ca81. Configure here.
| // Ignore span creation if: | ||
| // - the outgoing request is ignored via config | ||
| // - method is 'CONNECT' | ||
| if (request.method === 'CONNECT' || ignoredByCallback) { |
There was a problem hiding this comment.
Skipped requests lose trace headers
Medium Severity
With spans enabled, onRequestCreated returns before calling addTracePropagationHeadersToFetchRequest for CONNECT requests and when new URL fails, so outgoing headers are never injected. The removed SentryNodeFetchInstrumentation still ran on those requests and propagated trace data from the active scope.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d43ca81. Configure here.
There was a problem hiding this comment.
I think this is actually correct/expected.
size-limit report 📦
|
| SentryNodeFetchInstrumentation, | ||
| type SentryNodeFetchInstrumentationOptions, | ||
| } from './integrations/node-fetch/SentryNodeFetchInstrumentation'; | ||
| export { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from './utils/outgoingFetchRequest'; |
There was a problem hiding this comment.
super-l: Is this meant for users to be used as well? If not, I think prefixing it with _INTERNAL_ would be nice - not sure if we have a best practice for that, at least I always did it. And/or mark them as @internal in the JSDoc
There was a problem hiding this comment.
Ah. It seems it will be dropped again in the next PR :D
There was a problem hiding this comment.
yeah, this is a bit tricky 😅 should be cleaned up when I merge the stack together!
Stacked on #21872. Moves the `undici-instrumentation` (spans + breadcrumbs + trace propagation) and the vendored `node-fetch` types from the `node` package into `node-core`, and exposes `instrumentUndici` / `NodeFetchOptions` from `@sentry/node-core`. What changes: - `node-core`'s `nativeNodeFetchIntegration` now instruments via `instrumentUndici` directly (spans default to `true`). - The `node` package keeps a thin `nativeNodeFetchIntegration` wrapper (`node-fetch.ts`) that derives the `spans` default from the client options (`skipOpenTelemetrySetup` / `hasSpansEnabled`) before delegating to `instrumentUndici`. In v11 this will become the only implementation. - `SentryNodeFetchInstrumentation` is now unused internally and is marked `@deprecated`. It stays exported for backwards compatibility and will be removed in a future major version. Review the first PR in the stack (#21872) first — this PR is purely the relocation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>


Enhances the node
undici-instrumentationinto a single instrumentation that emitshttp.clientspans, records breadcrumbs, and propagates traces for outgoing fetch/undici requests. Previously this was split across two subscribers on the same diagnostics channels:instrumentUndici(spans) andSentryNodeFetchInstrumentation(breadcrumbs + trace propagation).What changes:
spansoption (defaulttrue). When spans are disabled, breadcrumbs are still recorded and trace propagation headers are still injected (gated bytracePropagation).addTracePropagationHeadersToFetchRequest, which gains an optionalspanargument so outgoing headers reference thehttp.clientspan while still de-duplicating against trace headers the user set manually (e.g. viagetTraceData()). This preserves the double-baggage prevention that the two-instrumentation setup previously provided.@sentry/node-corenow exportsaddFetchRequestBreadcrumbandaddTracePropagationHeadersToFetchRequestso the node instrumentation can reuse them.Root cause: folding the two subscribers into one dropped the de-dup pass that ran after span-based header injection; routing propagation through
addTracePropagationHeadersToFetchRequest(now span-aware) restores it.This PR is intentionally scoped to the
nodepackage (plus the minimalnode-coresupport above) to keep the diff reviewable. A stacked follow-up (#21873) moves the instrumentation intonode-core.🤖 Generated with Claude Code