1
1
import type { Hub } from '@sentry/core' ;
2
- import type { EventProcessor , Integration } from '@sentry/types' ;
2
+ import { getDynamicSamplingContextFromClient } from '@sentry/core' ;
3
+ import type { EventProcessor , Integration , Span } from '@sentry/types' ;
3
4
import {
4
5
dynamicRequire ,
5
6
dynamicSamplingContextToSentryBaggageHeader ,
7
+ generateSentryTraceHeader ,
6
8
getSanitizedUrlString ,
7
9
parseUrl ,
8
10
stringMatchesSomePattern ,
@@ -12,7 +14,13 @@ import { LRUMap } from 'lru_map';
12
14
import type { NodeClient } from '../../client' ;
13
15
import { NODE_VERSION } from '../../nodeVersion' ;
14
16
import { isSentryRequest } from '../utils/http' ;
15
- import type { DiagnosticsChannel , RequestCreateMessage , RequestEndMessage , RequestErrorMessage } from './types' ;
17
+ import type {
18
+ DiagnosticsChannel ,
19
+ RequestCreateMessage ,
20
+ RequestEndMessage ,
21
+ RequestErrorMessage ,
22
+ RequestWithSentry ,
23
+ } from './types' ;
16
24
17
25
export enum ChannelName {
18
26
// https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md#undicirequestcreate
@@ -124,63 +132,53 @@ export class Undici implements Integration {
124
132
const { request } = message as RequestCreateMessage ;
125
133
126
134
const stringUrl = request . origin ? request . origin . toString ( ) + request . path : request . path ;
127
- const url = parseUrl ( stringUrl ) ;
128
135
129
- if ( isSentryRequest ( stringUrl ) || request . __sentry__ !== undefined ) {
136
+ if ( isSentryRequest ( stringUrl ) || request . __sentry_span__ !== undefined ) {
130
137
return ;
131
138
}
132
139
133
140
const client = hub . getClient < NodeClient > ( ) ;
141
+ if ( ! client ) {
142
+ return ;
143
+ }
144
+
145
+ const clientOptions = client . getOptions ( ) ;
134
146
const scope = hub . getScope ( ) ;
135
147
136
- const activeSpan = scope . getSpan ( ) ;
137
-
138
- if ( activeSpan && client ) {
139
- const clientOptions = client . getOptions ( ) ;
140
-
141
- if ( shouldCreateSpan ( stringUrl ) ) {
142
- const method = request . method || 'GET' ;
143
- const data : Record < string , unknown > = {
144
- 'http.method' : method ,
145
- } ;
146
- if ( url . search ) {
147
- data [ 'http.query' ] = url . search ;
148
- }
149
- if ( url . hash ) {
150
- data [ 'http.fragment' ] = url . hash ;
151
- }
152
- const span = activeSpan . startChild ( {
153
- op : 'http.client' ,
154
- description : `${ method } ${ getSanitizedUrlString ( url ) } ` ,
155
- data,
156
- } ) ;
157
- request . __sentry__ = span ;
158
-
159
- const shouldAttachTraceData = ( url : string ) : boolean => {
160
- if ( clientOptions . tracePropagationTargets === undefined ) {
161
- return true ;
162
- }
163
-
164
- const cachedDecision = this . _headersUrlMap . get ( url ) ;
165
- if ( cachedDecision !== undefined ) {
166
- return cachedDecision ;
167
- }
168
-
169
- const decision = stringMatchesSomePattern ( url , clientOptions . tracePropagationTargets ) ;
170
- this . _headersUrlMap . set ( url , decision ) ;
171
- return decision ;
172
- } ;
173
-
174
- if ( shouldAttachTraceData ( stringUrl ) ) {
175
- request . addHeader ( 'sentry-trace' , span . toTraceparent ( ) ) ;
176
- if ( span . transaction ) {
177
- const dynamicSamplingContext = span . transaction . getDynamicSamplingContext ( ) ;
178
- const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader ( dynamicSamplingContext ) ;
179
- if ( sentryBaggageHeader ) {
180
- request . addHeader ( 'baggage' , sentryBaggageHeader ) ;
181
- }
182
- }
183
- }
148
+ const parentSpan = scope . getSpan ( ) ;
149
+
150
+ const span = shouldCreateSpan ( stringUrl ) ? createRequestSpan ( parentSpan , request , stringUrl ) : undefined ;
151
+ if ( span ) {
152
+ request . __sentry_span__ = span ;
153
+ }
154
+
155
+ const shouldAttachTraceData = ( url : string ) : boolean => {
156
+ if ( clientOptions . tracePropagationTargets === undefined ) {
157
+ return true ;
158
+ }
159
+
160
+ const cachedDecision = this . _headersUrlMap . get ( url ) ;
161
+ if ( cachedDecision !== undefined ) {
162
+ return cachedDecision ;
163
+ }
164
+
165
+ const decision = stringMatchesSomePattern ( url , clientOptions . tracePropagationTargets ) ;
166
+ this . _headersUrlMap . set ( url , decision ) ;
167
+ return decision ;
168
+ } ;
169
+
170
+ if ( shouldAttachTraceData ( stringUrl ) ) {
171
+ if ( span ) {
172
+ const dynamicSamplingContext = span ?. transaction ?. getDynamicSamplingContext ( ) ;
173
+ const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader ( dynamicSamplingContext ) ;
174
+
175
+ setHeadersOnRequest ( request , span . toTraceparent ( ) , sentryBaggageHeader ) ;
176
+ } else {
177
+ const { traceId, sampled, dsc } = scope . getPropagationContext ( ) ;
178
+ const sentryTrace = generateSentryTraceHeader ( traceId , undefined , sampled ) ;
179
+ const dynamicSamplingContext = dsc || getDynamicSamplingContextFromClient ( traceId , client , scope ) ;
180
+ const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader ( dynamicSamplingContext ) ;
181
+ setHeadersOnRequest ( request , sentryTrace , sentryBaggageHeader ) ;
184
182
}
185
183
}
186
184
} ) ;
@@ -199,7 +197,7 @@ export class Undici implements Integration {
199
197
return ;
200
198
}
201
199
202
- const span = request . __sentry__ ;
200
+ const span = request . __sentry_span__ ;
203
201
if ( span ) {
204
202
span . setHttpStatus ( response . statusCode ) ;
205
203
span . finish ( ) ;
@@ -239,7 +237,7 @@ export class Undici implements Integration {
239
237
return ;
240
238
}
241
239
242
- const span = request . __sentry__ ;
240
+ const span = request . __sentry_span__ ;
243
241
if ( span ) {
244
242
span . setStatus ( 'internal_error' ) ;
245
243
span . finish ( ) ;
@@ -265,3 +263,44 @@ export class Undici implements Integration {
265
263
} ) ;
266
264
}
267
265
}
266
+
267
+ function setHeadersOnRequest (
268
+ request : RequestWithSentry ,
269
+ sentryTrace : string ,
270
+ sentryBaggageHeader : string | undefined ,
271
+ ) : void {
272
+ if ( request . __sentry_has_headers__ ) {
273
+ return ;
274
+ }
275
+
276
+ request . addHeader ( 'sentry-trace' , sentryTrace ) ;
277
+ if ( sentryBaggageHeader ) {
278
+ request . addHeader ( 'baggage' , sentryBaggageHeader ) ;
279
+ }
280
+
281
+ request . __sentry_has_headers__ = true ;
282
+ }
283
+
284
+ function createRequestSpan (
285
+ activeSpan : Span | undefined ,
286
+ request : RequestWithSentry ,
287
+ stringUrl : string ,
288
+ ) : Span | undefined {
289
+ const url = parseUrl ( stringUrl ) ;
290
+
291
+ const method = request . method || 'GET' ;
292
+ const data : Record < string , unknown > = {
293
+ 'http.method' : method ,
294
+ } ;
295
+ if ( url . search ) {
296
+ data [ 'http.query' ] = url . search ;
297
+ }
298
+ if ( url . hash ) {
299
+ data [ 'http.fragment' ] = url . hash ;
300
+ }
301
+ return activeSpan ?. startChild ( {
302
+ op : 'http.client' ,
303
+ description : `${ method } ${ getSanitizedUrlString ( url ) } ` ,
304
+ data,
305
+ } ) ;
306
+ }
0 commit comments