1
1
import type { Hub , Scope , Span , SpanTimeInput , StartSpanOptions , TransactionContext } from '@sentry/types' ;
2
2
3
3
import { addNonEnumerableProperty , dropUndefinedKeys , logger , tracingContextFromHeaders } from '@sentry/utils' ;
4
+ import { getDynamicSamplingContextFromSpan } from '.' ;
4
5
import { getCurrentScope , getIsolationScope , withScope } from '../currentScopes' ;
5
6
6
7
import { DEBUG_BUILD } from '../debug-build' ;
7
8
import { getCurrentHub } from '../hub' ;
8
9
import { handleCallbackErrors } from '../utils/handleCallbackErrors' ;
9
10
import { hasTracingEnabled } from '../utils/hasTracingEnabled' ;
10
- import { spanTimeInputToSeconds , spanToJSON } from '../utils/spanUtils' ;
11
+ import { spanIsSampled , spanTimeInputToSeconds , spanToJSON } from '../utils/spanUtils' ;
11
12
12
13
/**
13
14
* Wraps a function with a transaction/span and finishes the span after the function is done.
@@ -21,7 +22,7 @@ import { spanTimeInputToSeconds, spanToJSON } from '../utils/spanUtils';
21
22
* and the `span` returned from the callback will be undefined.
22
23
*/
23
24
export function startSpan < T > ( context : StartSpanOptions , callback : ( span : Span | undefined ) => T ) : T {
24
- const ctx = normalizeContext ( context ) ;
25
+ const spanContext = normalizeContext ( context ) ;
25
26
26
27
return withScope ( context . scope , scope => {
27
28
// eslint-disable-next-line deprecation/deprecation
@@ -30,10 +31,14 @@ export function startSpan<T>(context: StartSpanOptions, callback: (span: Span |
30
31
const parentSpan = scope . getSpan ( ) ;
31
32
32
33
const shouldSkipSpan = context . onlyIfParent && ! parentSpan ;
33
- const activeSpan = shouldSkipSpan ? undefined : createChildSpanOrTransaction ( hub , parentSpan , ctx ) ;
34
-
35
- // eslint-disable-next-line deprecation/deprecation
36
- scope . setSpan ( activeSpan ) ;
34
+ const activeSpan = shouldSkipSpan
35
+ ? undefined
36
+ : createChildSpanOrTransaction ( hub , {
37
+ parentSpan,
38
+ spanContext,
39
+ forceTransaction : context . forceTransaction ,
40
+ scope,
41
+ } ) ;
37
42
38
43
return handleCallbackErrors (
39
44
( ) => callback ( activeSpan ) ,
@@ -66,7 +71,7 @@ export function startSpanManual<T>(
66
71
context : StartSpanOptions ,
67
72
callback : ( span : Span | undefined , finish : ( ) => void ) => T ,
68
73
) : T {
69
- const ctx = normalizeContext ( context ) ;
74
+ const spanContext = normalizeContext ( context ) ;
70
75
71
76
return withScope ( context . scope , scope => {
72
77
// eslint-disable-next-line deprecation/deprecation
@@ -75,10 +80,14 @@ export function startSpanManual<T>(
75
80
const parentSpan = scope . getSpan ( ) ;
76
81
77
82
const shouldSkipSpan = context . onlyIfParent && ! parentSpan ;
78
- const activeSpan = shouldSkipSpan ? undefined : createChildSpanOrTransaction ( hub , parentSpan , ctx ) ;
79
-
80
- // eslint-disable-next-line deprecation/deprecation
81
- scope . setSpan ( activeSpan ) ;
83
+ const activeSpan = shouldSkipSpan
84
+ ? undefined
85
+ : createChildSpanOrTransaction ( hub , {
86
+ parentSpan,
87
+ spanContext,
88
+ forceTransaction : context . forceTransaction ,
89
+ scope,
90
+ } ) ;
82
91
83
92
function finishAndSetSpan ( ) : void {
84
93
activeSpan && activeSpan . end ( ) ;
@@ -114,7 +123,7 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
114
123
return undefined ;
115
124
}
116
125
117
- const ctx = normalizeContext ( context ) ;
126
+ const spanContext = normalizeContext ( context ) ;
118
127
// eslint-disable-next-line deprecation/deprecation
119
128
const hub = getCurrentHub ( ) ;
120
129
const parentSpan = context . scope
@@ -128,41 +137,19 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
128
137
return undefined ;
129
138
}
130
139
131
- const isolationScope = getIsolationScope ( ) ;
132
- const scope = getCurrentScope ( ) ;
133
-
134
- let span : Span | undefined ;
135
-
136
- if ( parentSpan ) {
137
- // eslint-disable-next-line deprecation/deprecation
138
- span = parentSpan . startChild ( ctx ) ;
139
- } else {
140
- const { traceId, dsc, parentSpanId, sampled } = {
141
- ...isolationScope . getPropagationContext ( ) ,
142
- ...scope . getPropagationContext ( ) ,
143
- } ;
144
-
145
- // eslint-disable-next-line deprecation/deprecation
146
- span = hub . startTransaction ( {
147
- traceId,
148
- parentSpanId,
149
- parentSampled : sampled ,
150
- ...ctx ,
151
- metadata : {
152
- dynamicSamplingContext : dsc ,
153
- // eslint-disable-next-line deprecation/deprecation
154
- ...ctx . metadata ,
155
- } ,
156
- } ) ;
157
- }
158
-
159
- if ( parentSpan ) {
160
- addChildSpanToSpan ( parentSpan , span ) ;
161
- }
140
+ const scope = context . scope || getCurrentScope ( ) ;
162
141
163
- setCapturedScopesOnSpan ( span , scope , isolationScope ) ;
142
+ // Even though we don't actually want to make this span active on the current scope,
143
+ // we need to make it active on a temporary scope that we use for event processing
144
+ // as otherwise, it won't pick the correct span for the event when processing it
145
+ const temporaryScope = scope . clone ( ) ;
164
146
165
- return span ;
147
+ return createChildSpanOrTransaction ( hub , {
148
+ parentSpan,
149
+ spanContext,
150
+ forceTransaction : context . forceTransaction ,
151
+ scope : temporaryScope ,
152
+ } ) ;
166
153
}
167
154
168
155
/**
@@ -277,20 +264,47 @@ export const continueTrace: ContinueTrace = <V>(
277
264
278
265
function createChildSpanOrTransaction (
279
266
hub : Hub ,
280
- parentSpan : Span | undefined ,
281
- ctx : TransactionContext ,
267
+ {
268
+ parentSpan,
269
+ spanContext,
270
+ forceTransaction,
271
+ scope,
272
+ } : {
273
+ parentSpan : Span | undefined ;
274
+ spanContext : TransactionContext ;
275
+ forceTransaction ?: boolean ;
276
+ scope : Scope ;
277
+ } ,
282
278
) : Span | undefined {
283
279
if ( ! hasTracingEnabled ( ) ) {
284
280
return undefined ;
285
281
}
286
282
287
283
const isolationScope = getIsolationScope ( ) ;
288
- const scope = getCurrentScope ( ) ;
289
284
290
285
let span : Span | undefined ;
291
- if ( parentSpan ) {
286
+ if ( parentSpan && ! forceTransaction ) {
287
+ // eslint-disable-next-line deprecation/deprecation
288
+ span = parentSpan . startChild ( spanContext ) ;
289
+ addChildSpanToSpan ( parentSpan , span ) ;
290
+ } else if ( parentSpan ) {
291
+ // If we forced a transaction but have a parent span, make sure to continue from the parent span, not the scope
292
+ const dsc = getDynamicSamplingContextFromSpan ( parentSpan ) ;
293
+ const { traceId, spanId : parentSpanId } = parentSpan . spanContext ( ) ;
294
+ const sampled = spanIsSampled ( parentSpan ) ;
295
+
292
296
// eslint-disable-next-line deprecation/deprecation
293
- span = parentSpan . startChild ( ctx ) ;
297
+ span = hub . startTransaction ( {
298
+ traceId,
299
+ parentSpanId,
300
+ parentSampled : sampled ,
301
+ ...spanContext ,
302
+ metadata : {
303
+ dynamicSamplingContext : dsc ,
304
+ // eslint-disable-next-line deprecation/deprecation
305
+ ...spanContext . metadata ,
306
+ } ,
307
+ } ) ;
294
308
} else {
295
309
const { traceId, dsc, parentSpanId, sampled } = {
296
310
...isolationScope . getPropagationContext ( ) ,
@@ -302,18 +316,20 @@ function createChildSpanOrTransaction(
302
316
traceId,
303
317
parentSpanId,
304
318
parentSampled : sampled ,
305
- ...ctx ,
319
+ ...spanContext ,
306
320
metadata : {
307
321
dynamicSamplingContext : dsc ,
308
322
// eslint-disable-next-line deprecation/deprecation
309
- ...ctx . metadata ,
323
+ ...spanContext . metadata ,
310
324
} ,
311
325
} ) ;
312
326
}
313
327
314
- if ( parentSpan ) {
315
- addChildSpanToSpan ( parentSpan , span ) ;
316
- }
328
+ // We always set this as active span on the scope
329
+ // In the case of this being an inactive span, we ensure to pass a detached scope in here in the first place
330
+ // But by having this here, we can ensure that the lookup through `getCapturedScopesOnSpan` results in the correct scope & span combo
331
+ // eslint-disable-next-line deprecation/deprecation
332
+ scope . setSpan ( span ) ;
317
333
318
334
setCapturedScopesOnSpan ( span , scope , isolationScope ) ;
319
335
0 commit comments