From 644188e138fcbd518e52f99020e09baaec9d79c5 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 19 Mar 2025 13:51:43 +0100 Subject: [PATCH 1/2] docs(node): Add explanation for second http instrumentation --- .../http/SentryHttpInstrumentationBeforeOtel.ts | 11 +++++++++++ packages/node/src/integrations/http/index.ts | 10 +++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/node/src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts b/packages/node/src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts index 335f23604e10..a9d8bcf1b116 100644 --- a/packages/node/src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts +++ b/packages/node/src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts @@ -9,6 +9,17 @@ import { stealthWrap } from './utils'; type Http = typeof http; type Https = typeof https; +// The reason this "before OTEL" integration even exists is due to timing reasons. We need to be able to register a +// `res.on('close')` handler **after** OTEL registers its own handler (which it uses to end spans), so that we can do +// something (ie. flush) after OTEL has ended a span for a request. If you think about it like an onion: +// +// (Sentry after OTEL instrumentation +// (OTEL instrumentation +// (Sentry before OTEL instrumentation +// (orig HTTP request handler)))) +// +// registering an instrumentation before OTEL allows us to do this for incoming requests. + /** * A Sentry specific http instrumentation that is applied before the otel instrumentation. */ diff --git a/packages/node/src/integrations/http/index.ts b/packages/node/src/integrations/http/index.ts index 6e7581b75c8d..31ec29e149f1 100644 --- a/packages/node/src/integrations/http/index.ts +++ b/packages/node/src/integrations/http/index.ts @@ -148,6 +148,12 @@ export const httpIntegration = defineIntegration((options: HttpOptions = {}) => return { name: INTEGRATION_NAME, setupOnce() { + // Below, we instrument the Node.js HTTP API three times. 2 times Sentry-specific, 1 time OTEL specific. + // Due to timing reasons, we sometimes need to apply Sentry instrumentation _before_ we apply the OTEL + // instrumentation (e.g. to flush on serverless platforms), and sometimes we need to apply Sentry instrumentation + // _after_ we apply OTEL instrumentation (e.g. for isolation scope handling and breadcrumbs). + + // This is Sentry-specific instrumentation that is applied _before_ any OTEL instrumentation. instrumentSentryHttpBeforeOtel(); const instrumentSpans = _shouldInstrumentSpans(options, getClient()?.getOptions()); @@ -158,9 +164,7 @@ export const httpIntegration = defineIntegration((options: HttpOptions = {}) => instrumentOtelHttp(instrumentationConfig); } - // This is the Sentry-specific instrumentation that isolates requests & creates breadcrumbs - // Note that this _has_ to be wrapped after the OTEL instrumentation, - // otherwise the isolation will not work correctly + // This is Sentry-specific instrumentation that is applied _after_ any OTEL instrumentation. instrumentSentryHttp(options); }, }; From 495e082c878e49b236c0d8be47cf88f049ae61f9 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Thu, 20 Mar 2025 10:47:39 +0100 Subject: [PATCH 2/2] Short circuit for vercel --- packages/node/src/integrations/http/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/node/src/integrations/http/index.ts b/packages/node/src/integrations/http/index.ts index 31ec29e149f1..25817e29dad4 100644 --- a/packages/node/src/integrations/http/index.ts +++ b/packages/node/src/integrations/http/index.ts @@ -154,7 +154,11 @@ export const httpIntegration = defineIntegration((options: HttpOptions = {}) => // _after_ we apply OTEL instrumentation (e.g. for isolation scope handling and breadcrumbs). // This is Sentry-specific instrumentation that is applied _before_ any OTEL instrumentation. - instrumentSentryHttpBeforeOtel(); + if (process.env.VERCEL) { + // Currently this instrumentation only does something when deployed on Vercel, so to save some overhead, we short circuit adding it here only for Vercel. + // If it's functionality is extended in the future, feel free to remove the if statement and this comment. + instrumentSentryHttpBeforeOtel(); + } const instrumentSpans = _shouldInstrumentSpans(options, getClient()?.getOptions());