11import  type  {  Hub ,  Scope ,  Span ,  SpanTimeInput ,  StartSpanOptions ,  TransactionContext  }  from  '@sentry/types' ; 
22
33import  {  addNonEnumerableProperty ,  dropUndefinedKeys ,  logger ,  tracingContextFromHeaders  }  from  '@sentry/utils' ; 
4+ import  {  getDynamicSamplingContextFromSpan  }  from  '.' ; 
45import  {  getCurrentScope ,  getIsolationScope ,  withScope  }  from  '../currentScopes' ; 
56
67import  {  DEBUG_BUILD  }  from  '../debug-build' ; 
78import  {  getCurrentHub  }  from  '../hub' ; 
89import  {  handleCallbackErrors  }  from  '../utils/handleCallbackErrors' ; 
910import  {  hasTracingEnabled  }  from  '../utils/hasTracingEnabled' ; 
10- import  {  spanTimeInputToSeconds ,  spanToJSON  }  from  '../utils/spanUtils' ; 
11+ import  {  spanIsSampled ,   spanTimeInputToSeconds ,  spanToJSON  }  from  '../utils/spanUtils' ; 
1112
1213/** 
1314 * 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';
2122 * and the `span` returned from the callback will be undefined. 
2223 */ 
2324export  function  startSpan < T > ( context : StartSpanOptions ,  callback : ( span : Span  |  undefined )  =>  T ) : T  { 
24-   const  ctx  =  normalizeContext ( context ) ; 
25+   const  spanContext  =  normalizeContext ( context ) ; 
2526
2627  return  withScope ( context . scope ,  scope  =>  { 
2728    // eslint-disable-next-line deprecation/deprecation 
@@ -30,10 +31,14 @@ export function startSpan<T>(context: StartSpanOptions, callback: (span: Span |
3031    const  parentSpan  =  scope . getSpan ( ) ; 
3132
3233    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+         } ) ; 
3742
3843    return  handleCallbackErrors ( 
3944      ( )  =>  callback ( activeSpan ) , 
@@ -66,7 +71,7 @@ export function startSpanManual<T>(
6671  context : StartSpanOptions , 
6772  callback : ( span : Span  |  undefined ,  finish : ( )  =>  void )  =>  T , 
6873) : T  { 
69-   const  ctx  =  normalizeContext ( context ) ; 
74+   const  spanContext  =  normalizeContext ( context ) ; 
7075
7176  return  withScope ( context . scope ,  scope  =>  { 
7277    // eslint-disable-next-line deprecation/deprecation 
@@ -75,10 +80,14 @@ export function startSpanManual<T>(
7580    const  parentSpan  =  scope . getSpan ( ) ; 
7681
7782    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+         } ) ; 
8291
8392    function  finishAndSetSpan ( ) : void { 
8493      activeSpan  &&  activeSpan . end ( ) ; 
@@ -114,7 +123,7 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
114123    return  undefined ; 
115124  } 
116125
117-   const  ctx  =  normalizeContext ( context ) ; 
126+   const  spanContext  =  normalizeContext ( context ) ; 
118127  // eslint-disable-next-line deprecation/deprecation 
119128  const  hub  =  getCurrentHub ( ) ; 
120129  const  parentSpan  =  context . scope 
@@ -128,41 +137,19 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
128137    return  undefined ; 
129138  } 
130139
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 ( ) ; 
162141
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 ( ) ; 
164146
165-   return  span ; 
147+   return  createChildSpanOrTransaction ( hub ,  { 
148+     parentSpan, 
149+     spanContext, 
150+     forceTransaction : context . forceTransaction , 
151+     scope : temporaryScope , 
152+   } ) ; 
166153} 
167154
168155/** 
@@ -277,20 +264,47 @@ export const continueTrace: ContinueTrace = <V>(
277264
278265function  createChildSpanOrTransaction ( 
279266  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+   } , 
282278) : Span  |  undefined  { 
283279  if  ( ! hasTracingEnabled ( ) )  { 
284280    return  undefined ; 
285281  } 
286282
287283  const  isolationScope  =  getIsolationScope ( ) ; 
288-   const  scope  =  getCurrentScope ( ) ; 
289284
290285  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+ 
292296    // 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+     } ) ; 
294308  }  else  { 
295309    const  {  traceId,  dsc,  parentSpanId,  sampled }  =  { 
296310      ...isolationScope . getPropagationContext ( ) , 
@@ -302,18 +316,20 @@ function createChildSpanOrTransaction(
302316      traceId, 
303317      parentSpanId, 
304318      parentSampled : sampled , 
305-       ...ctx , 
319+       ...spanContext , 
306320      metadata : { 
307321        dynamicSamplingContext : dsc , 
308322        // eslint-disable-next-line deprecation/deprecation 
309-         ...ctx . metadata , 
323+         ...spanContext . metadata , 
310324      } , 
311325    } ) ; 
312326  } 
313327
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 ) ; 
317333
318334  setCapturedScopesOnSpan ( span ,  scope ,  isolationScope ) ; 
319335
0 commit comments