66 stringMatchesSomePattern ,
77 stripUrlQueryAndFragment ,
88} from '@sentry/utils' ;
9+ import { LRUMap } from 'lru_map' ;
910
1011import type { NodeClient } from '../../client' ;
1112import { NODE_VERSION } from '../../nodeVersion' ;
@@ -29,7 +30,7 @@ export interface UndiciOptions {
2930 * Function determining whether or not to create spans to track outgoing requests to the given URL.
3031 * By default, spans will be created for all outgoing requests.
3132 */
32- shouldCreateSpanForRequest : ( url : string ) => boolean ;
33+ shouldCreateSpanForRequest ? : ( url : string ) => boolean ;
3334}
3435
3536// Please note that you cannot use `console.log` to debug the callbacks registered to the `diagnostics_channel` API.
@@ -57,10 +58,13 @@ export class Undici implements Integration {
5758
5859 private readonly _options : UndiciOptions ;
5960
61+ private readonly _createSpanUrlMap : LRUMap < string , boolean > = new LRUMap ( 100 ) ;
62+ private readonly _headersUrlMap : LRUMap < string , boolean > = new LRUMap ( 100 ) ;
63+
6064 public constructor ( _options : Partial < UndiciOptions > = { } ) {
6165 this . _options = {
6266 breadcrumbs : _options . breadcrumbs === undefined ? true : _options . breadcrumbs ,
63- shouldCreateSpanForRequest : _options . shouldCreateSpanForRequest || ( ( ) => true ) ,
67+ shouldCreateSpanForRequest : _options . shouldCreateSpanForRequest ,
6468 } ;
6569 }
6670
@@ -85,6 +89,21 @@ export class Undici implements Integration {
8589 return ;
8690 }
8791
92+ const shouldCreateSpan = ( url : string ) : boolean => {
93+ if ( this . _options . shouldCreateSpanForRequest === undefined ) {
94+ return true ;
95+ }
96+
97+ const cachedDecision = this . _createSpanUrlMap . get ( url ) ;
98+ if ( cachedDecision !== undefined ) {
99+ return cachedDecision ;
100+ }
101+
102+ const decision = this . _options . shouldCreateSpanForRequest ( url ) ;
103+ this . _createSpanUrlMap . set ( url , decision ) ;
104+ return decision ;
105+ } ;
106+
88107 // https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md
89108 ds . subscribe ( ChannelName . RequestCreate , message => {
90109 const hub = getCurrentHub ( ) ;
@@ -108,9 +127,8 @@ export class Undici implements Integration {
108127
109128 if ( activeSpan && client ) {
110129 const clientOptions = client . getOptions ( ) ;
111- const shouldCreateSpan = this . _options . shouldCreateSpanForRequest ( stringUrl ) ;
112130
113- if ( shouldCreateSpan ) {
131+ if ( shouldCreateSpan ( stringUrl ) ) {
114132 const method = request . method || 'GET' ;
115133 const data : Record < string , unknown > = {
116134 'http.method' : method ,
@@ -129,11 +147,22 @@ export class Undici implements Integration {
129147 } ) ;
130148 request . __sentry__ = span ;
131149
132- const shouldPropagate = clientOptions . tracePropagationTargets
133- ? stringMatchesSomePattern ( stringUrl , clientOptions . tracePropagationTargets )
134- : true ;
150+ const shouldAttachTraceData = ( url : string ) : boolean => {
151+ if ( clientOptions . tracePropagationTargets === undefined ) {
152+ return true ;
153+ }
154+
155+ const cachedDecision = this . _headersUrlMap . get ( url ) ;
156+ if ( cachedDecision !== undefined ) {
157+ return cachedDecision ;
158+ }
159+
160+ const decision = stringMatchesSomePattern ( url , clientOptions . tracePropagationTargets ) ;
161+ this . _headersUrlMap . set ( url , decision ) ;
162+ return decision ;
163+ } ;
135164
136- if ( shouldPropagate ) {
165+ if ( shouldAttachTraceData ( stringUrl ) ) {
137166 request . addHeader ( 'sentry-trace' , span . toTraceparent ( ) ) ;
138167 if ( span . transaction ) {
139168 const dynamicSamplingContext = span . transaction . getDynamicSamplingContext ( ) ;
0 commit comments