6
6
stringMatchesSomePattern ,
7
7
stripUrlQueryAndFragment ,
8
8
} from '@sentry/utils' ;
9
+ import { LRUMap } from 'lru_map' ;
9
10
10
11
import type { NodeClient } from '../../client' ;
11
12
import { NODE_VERSION } from '../../nodeVersion' ;
@@ -29,7 +30,7 @@ export interface UndiciOptions {
29
30
* Function determining whether or not to create spans to track outgoing requests to the given URL.
30
31
* By default, spans will be created for all outgoing requests.
31
32
*/
32
- shouldCreateSpanForRequest : ( url : string ) => boolean ;
33
+ shouldCreateSpanForRequest ? : ( url : string ) => boolean ;
33
34
}
34
35
35
36
// 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 {
57
58
58
59
private readonly _options : UndiciOptions ;
59
60
61
+ private readonly _createSpanUrlMap : LRUMap < string , boolean > = new LRUMap ( 100 ) ;
62
+ private readonly _headersUrlMap : LRUMap < string , boolean > = new LRUMap ( 100 ) ;
63
+
60
64
public constructor ( _options : Partial < UndiciOptions > = { } ) {
61
65
this . _options = {
62
66
breadcrumbs : _options . breadcrumbs === undefined ? true : _options . breadcrumbs ,
63
- shouldCreateSpanForRequest : _options . shouldCreateSpanForRequest || ( ( ) => true ) ,
67
+ shouldCreateSpanForRequest : _options . shouldCreateSpanForRequest ,
64
68
} ;
65
69
}
66
70
@@ -85,6 +89,21 @@ export class Undici implements Integration {
85
89
return ;
86
90
}
87
91
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
+
88
107
// https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md
89
108
ds . subscribe ( ChannelName . RequestCreate , message => {
90
109
const hub = getCurrentHub ( ) ;
@@ -108,9 +127,8 @@ export class Undici implements Integration {
108
127
109
128
if ( activeSpan && client ) {
110
129
const clientOptions = client . getOptions ( ) ;
111
- const shouldCreateSpan = this . _options . shouldCreateSpanForRequest ( stringUrl ) ;
112
130
113
- if ( shouldCreateSpan ) {
131
+ if ( shouldCreateSpan ( stringUrl ) ) {
114
132
const method = request . method || 'GET' ;
115
133
const data : Record < string , unknown > = {
116
134
'http.method' : method ,
@@ -129,11 +147,22 @@ export class Undici implements Integration {
129
147
} ) ;
130
148
request . __sentry__ = span ;
131
149
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
+ } ;
135
164
136
- if ( shouldPropagate ) {
165
+ if ( shouldAttachTraceData ( stringUrl ) ) {
137
166
request . addHeader ( 'sentry-trace' , span . toTraceparent ( ) ) ;
138
167
if ( span . transaction ) {
139
168
const dynamicSamplingContext = span . transaction . getDynamicSamplingContext ( ) ;
0 commit comments