11/* eslint-disable max-lines */
2- import type * as http from 'node:http' ;
3- import type { IncomingMessage , RequestOptions } from 'node:http' ;
4- import type * as https from 'node:https' ;
5- import type { EventEmitter } from 'node:stream' ;
2+ import { context , propagation } from '@opentelemetry/api' ;
63import { VERSION } from '@opentelemetry/core' ;
74import type { InstrumentationConfig } from '@opentelemetry/instrumentation' ;
85import { InstrumentationBase , InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation' ;
@@ -12,31 +9,44 @@ import {
129 generateSpanId ,
1310 getBreadcrumbLogLevelFromHttpStatusCode ,
1411 getClient ,
12+ getCurrentScope ,
1513 getIsolationScope ,
1614 getSanitizedUrlString ,
1715 httpRequestToRequestData ,
1816 logger ,
1917 parseUrl ,
2018 stripUrlQueryAndFragment ,
2119 withIsolationScope ,
22- withScope ,
2320} from '@sentry/core' ;
21+ import type * as http from 'node:http' ;
22+ import type { IncomingMessage , RequestOptions } from 'node:http' ;
23+ import type * as https from 'node:https' ;
24+ import type { EventEmitter } from 'node:stream' ;
2425import { DEBUG_BUILD } from '../../debug-build' ;
2526import { getRequestUrl } from '../../utils/getRequestUrl' ;
26- import { getRequestInfo } from './vendor/getRequestInfo' ;
2727import { stealthWrap } from './utils' ;
28+ import { getRequestInfo } from './vendor/getRequestInfo' ;
2829
2930type Http = typeof http ;
3031type Https = typeof https ;
3132
32- type SentryHttpInstrumentationOptions = InstrumentationConfig & {
33+ export type SentryHttpInstrumentationOptions = InstrumentationConfig & {
3334 /**
3435 * Whether breadcrumbs should be recorded for requests.
3536 *
3637 * @default `true`
3738 */
3839 breadcrumbs ?: boolean ;
3940
41+ /**
42+ * Whether to extract the trace ID from the `sentry-trace` header for incoming requests.
43+ * By default this is done by the HttpInstrumentation, but if that is not added (e.g. because tracing is disabled, ...)
44+ * then this instrumentation can take over.
45+ *
46+ * @default `false`
47+ */
48+ extractIncomingTraceFromHeader ?: boolean ;
49+
4050 /**
4151 * Do not capture breadcrumbs for outgoing HTTP requests to URLs where the given callback returns `true`.
4252 * For the scope of this instrumentation, this callback only controls breadcrumb creation.
@@ -185,9 +195,18 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
185195 }
186196
187197 return withIsolationScope ( isolationScope , ( ) => {
188- return withScope ( scope => {
189- // Set a new propagationSpanId for this request
190- scope . getPropagationContext ( ) . propagationSpanId = generateSpanId ( ) ;
198+ // Set a new propagationSpanId for this request
199+ // We rely on the fact that `withIsolationScope()` will implicitly also fork the current scope
200+ // This way we can save an "unnecessary" `withScope()` invocation
201+ getCurrentScope ( ) . getPropagationContext ( ) . propagationSpanId = generateSpanId ( ) ;
202+
203+ // If we don't want to extract the trace from the header, we can skip this
204+ if ( ! instrumentation . getConfig ( ) . extractIncomingTraceFromHeader ) {
205+ return original . apply ( this , [ event , ...args ] ) ;
206+ }
207+
208+ const ctx = propagation . extract ( context . active ( ) , normalizedRequest . headers ) ;
209+ return context . with ( ctx , ( ) => {
191210 return original . apply ( this , [ event , ...args ] ) ;
192211 } ) ;
193212 } ) ;
0 commit comments