1- import { getCurrentHub } from '@sentry/core' ;
2- import { Integration , Span } from '@sentry/types' ;
3- import { fill , logger , mergeAndSerializeBaggage , parseSemver } from '@sentry/utils' ;
1+ import { getCurrentHub , Hub } from '@sentry/core' ;
2+ import { EventProcessor , Integration , Span , TracePropagationTargets } from '@sentry/types' ;
3+ import { fill , isMatchingPattern , logger , mergeAndSerializeBaggage , parseSemver } from '@sentry/utils' ;
44import * as http from 'http' ;
55import * as https from 'https' ;
66
7+ import { NodeClientOptions } from '../types' ;
78import {
89 cleanSpanDescription ,
910 extractUrl ,
@@ -15,7 +16,10 @@ import {
1516
1617const NODE_VERSION = parseSemver ( process . versions . node ) ;
1718
18- /** http module integration */
19+ /**
20+ * The http module integration instruments Node's internal http module. It creates breadcrumbs, transactions for outgoing
21+ * http requests and attaches trace data when tracing is enabled via its `tracing` option.
22+ */
1923export class Http implements Integration {
2024 /**
2125 * @inheritDoc
@@ -48,13 +52,22 @@ export class Http implements Integration {
4852 /**
4953 * @inheritDoc
5054 */
51- public setupOnce ( ) : void {
55+ public setupOnce (
56+ _addGlobalEventProcessor : ( callback : EventProcessor ) => void ,
57+ setupOnceGetCurrentHub : ( ) => Hub ,
58+ ) : void {
5259 // No need to instrument if we don't want to track anything
5360 if ( ! this . _breadcrumbs && ! this . _tracing ) {
5461 return ;
5562 }
5663
57- const wrappedHandlerMaker = _createWrappedRequestMethodFactory ( this . _breadcrumbs , this . _tracing ) ;
64+ const clientOptions = setupOnceGetCurrentHub ( ) . getClient ( ) ?. getOptions ( ) as NodeClientOptions | undefined ;
65+
66+ const wrappedHandlerMaker = _createWrappedRequestMethodFactory (
67+ this . _breadcrumbs ,
68+ this . _tracing ,
69+ clientOptions ?. tracePropagationTargets ,
70+ ) ;
5871
5972 // eslint-disable-next-line @typescript-eslint/no-var-requires
6073 const httpModule = require ( 'http' ) ;
@@ -90,7 +103,26 @@ type WrappedRequestMethodFactory = (original: OriginalRequestMethod) => WrappedR
90103function _createWrappedRequestMethodFactory (
91104 breadcrumbsEnabled : boolean ,
92105 tracingEnabled : boolean ,
106+ tracePropagationTargets : TracePropagationTargets | undefined ,
93107) : WrappedRequestMethodFactory {
108+ // We're caching results so we dont have to recompute regexp everytime we create a request.
109+ const urlMap : Record < string , boolean > = { } ;
110+ const shouldAttachTraceData = ( url : string ) : boolean => {
111+ if ( tracePropagationTargets === undefined ) {
112+ return true ;
113+ }
114+
115+ if ( urlMap [ url ] ) {
116+ return urlMap [ url ] ;
117+ }
118+
119+ urlMap [ url ] = tracePropagationTargets . some ( tracePropagationTarget =>
120+ isMatchingPattern ( url , tracePropagationTarget ) ,
121+ ) ;
122+
123+ return urlMap [ url ] ;
124+ } ;
125+
94126 return function wrappedRequestMethodFactory ( originalRequestMethod : OriginalRequestMethod ) : WrappedRequestMethod {
95127 return function wrappedMethod ( this : typeof http | typeof https , ...args : RequestMethodArgs ) : http . ClientRequest {
96128 // eslint-disable-next-line @typescript-eslint/no-this-alias
@@ -109,28 +141,37 @@ function _createWrappedRequestMethodFactory(
109141 let parentSpan : Span | undefined ;
110142
111143 const scope = getCurrentHub ( ) . getScope ( ) ;
144+
112145 if ( scope && tracingEnabled ) {
113146 parentSpan = scope . getSpan ( ) ;
147+
114148 if ( parentSpan ) {
115149 span = parentSpan . startChild ( {
116150 description : `${ requestOptions . method || 'GET' } ${ requestUrl } ` ,
117151 op : 'http.client' ,
118152 } ) ;
119153
120- const sentryTraceHeader = span . toTraceparent ( ) ;
121- __DEBUG_BUILD__ &&
122- logger . log (
123- `[Tracing] Adding sentry-trace header ${ sentryTraceHeader } to outgoing request to ${ requestUrl } : ` ,
124- ) ;
125-
126- const baggage = parentSpan . transaction && parentSpan . transaction . getBaggage ( ) ;
127- const headerBaggageString = requestOptions . headers && requestOptions . headers . baggage ;
128-
129- requestOptions . headers = {
130- ...requestOptions . headers ,
131- 'sentry-trace' : sentryTraceHeader ,
132- baggage : mergeAndSerializeBaggage ( baggage , headerBaggageString ) ,
133- } ;
154+ if ( shouldAttachTraceData ( requestUrl ) ) {
155+ const sentryTraceHeader = span . toTraceparent ( ) ;
156+ __DEBUG_BUILD__ &&
157+ logger . log (
158+ `[Tracing] Adding sentry-trace header ${ sentryTraceHeader } to outgoing request to "${ requestUrl } ": ` ,
159+ ) ;
160+
161+ const baggage = parentSpan . transaction && parentSpan . transaction . getBaggage ( ) ;
162+ const headerBaggageString = requestOptions . headers && requestOptions . headers . baggage ;
163+
164+ requestOptions . headers = {
165+ ...requestOptions . headers ,
166+ 'sentry-trace' : sentryTraceHeader ,
167+ baggage : mergeAndSerializeBaggage ( baggage , headerBaggageString ) ,
168+ } ;
169+ } else {
170+ __DEBUG_BUILD__ &&
171+ logger . log (
172+ `[Tracing] Not adding sentry-trace header to outgoing request (${ requestUrl } ) due to mismatching tracePropagationTargets option.` ,
173+ ) ;
174+ }
134175 }
135176 }
136177
0 commit comments