1- import  type  {  Context ,  Span ,  SpanOptions ,  Tracer  }  from  '@opentelemetry/api' ; 
1+ import  type  {  Context ,  Span ,  SpanContext ,  SpanOptions ,  Tracer  }  from  '@opentelemetry/api' ; 
2+ import  {  TraceFlags  }  from  '@opentelemetry/api' ; 
23import  {  context  }  from  '@opentelemetry/api' ; 
34import  {  SpanStatusCode ,  trace  }  from  '@opentelemetry/api' ; 
4- import  {  suppressTracing  }  from  '@opentelemetry/core' ; 
5+ import  {  TraceState ,   suppressTracing  }  from  '@opentelemetry/core' ; 
56import  {  SDK_VERSION ,  getClient ,  getCurrentScope ,  handleCallbackErrors  }  from  '@sentry/core' ; 
67import  type  {  Client ,  Scope  }  from  '@sentry/types' ; 
8+ import  {  dynamicSamplingContextToSentryBaggageHeader  }  from  '@sentry/utils' ; 
9+ import  {  SENTRY_TRACE_STATE_DSC  }  from  './constants' ; 
710
811import  {  InternalSentrySemanticAttributes  }  from  './semanticAttributes' ; 
912import  type  {  OpenTelemetryClient ,  OpenTelemetrySpanContext  }  from  './types' ; 
1013import  {  getContextFromScope  }  from  './utils/contextData' ; 
14+ import  {  getDynamicSamplingContextFromSpan  }  from  './utils/dynamicSamplingContext' ; 
15+ import  {  getRootSpan  }  from  './utils/getActiveSpan' ; 
1116import  {  setSpanMetadata  }  from  './utils/spanData' ; 
1217
1318/** 
@@ -24,7 +29,7 @@ export function startSpan<T>(options: OpenTelemetrySpanContext, callback: (span:
2429
2530  const  {  name }  =  options ; 
2631
27-   const  activeCtx  =  getContext ( options . scope ) ; 
32+   const  activeCtx  =  getContext ( options . scope ,   options . forceTransaction ) ; 
2833  const  shouldSkipSpan  =  options . onlyIfParent  &&  ! trace . getSpan ( activeCtx ) ; 
2934  const  ctx  =  shouldSkipSpan  ? suppressTracing ( activeCtx )  : activeCtx ; 
3035
@@ -57,7 +62,7 @@ export function startSpanManual<T>(options: OpenTelemetrySpanContext, callback:
5762
5863  const  {  name }  =  options ; 
5964
60-   const  activeCtx  =  getContext ( options . scope ) ; 
65+   const  activeCtx  =  getContext ( options . scope ,   options . forceTransaction ) ; 
6166  const  shouldSkipSpan  =  options . onlyIfParent  &&  ! trace . getSpan ( activeCtx ) ; 
6267  const  ctx  =  shouldSkipSpan  ? suppressTracing ( activeCtx )  : activeCtx ; 
6368
@@ -95,7 +100,7 @@ export function startInactiveSpan(options: OpenTelemetrySpanContext): Span {
95100
96101  const  {  name }  =  options ; 
97102
98-   const  activeCtx  =  getContext ( options . scope ) ; 
103+   const  activeCtx  =  getContext ( options . scope ,   options . forceTransaction ) ; 
99104  const  shouldSkipSpan  =  options . onlyIfParent  &&  ! trace . getSpan ( activeCtx ) ; 
100105  const  ctx  =  shouldSkipSpan  ? suppressTracing ( activeCtx )  : activeCtx ; 
101106
@@ -166,7 +171,50 @@ function ensureTimestampInMilliseconds(timestamp: number): number {
166171  return  isMs  ? timestamp  *  1000  : timestamp ; 
167172} 
168173
169- function  getContext ( scope ?: Scope ) : Context  { 
174+ function  getContext ( scope : Scope  |  undefined ,  forceTransaction : boolean  |  undefined ) : Context  { 
175+   const  ctx  =  getContextForScope ( scope ) ; 
176+ 
177+   if  ( ! forceTransaction )  { 
178+     return  ctx ; 
179+   } 
180+ 
181+   // Else we need to "fix" the context to have no parent span 
182+   const  parentSpan  =  trace . getSpan ( ctx ) ; 
183+ 
184+   // If there is no parent span, all good, nothing to do! 
185+   if  ( ! parentSpan )  { 
186+     return  ctx ; 
187+   } 
188+ 
189+   // Else, we need to do two things: 
190+   // 1. Unset the parent span from the context, so we'll create a new root span 
191+   // 2. Ensure the propagation context is correct, so we'll continue from the parent span 
192+   const  ctxWithoutSpan  =  trace . deleteSpan ( ctx ) ; 
193+ 
194+   const  {  spanId,  traceId,  traceFlags }  =  parentSpan . spanContext ( ) ; 
195+   // eslint-disable-next-line no-bitwise 
196+   const  sampled  =  Boolean ( traceFlags  &  TraceFlags . SAMPLED ) ; 
197+ 
198+   const  rootSpan  =  getRootSpan ( parentSpan ) ; 
199+   const  dsc  =  getDynamicSamplingContextFromSpan ( rootSpan ) ; 
200+   const  dscString  =  dynamicSamplingContextToSentryBaggageHeader ( dsc ) ; 
201+ 
202+   const  traceState  =  dscString  ? new  TraceState ( ) . set ( SENTRY_TRACE_STATE_DSC ,  dscString )  : undefined ; 
203+ 
204+   const  spanContext : SpanContext  =  { 
205+     traceId, 
206+     spanId, 
207+     isRemote : true , 
208+     traceFlags : sampled  ? TraceFlags . SAMPLED  : TraceFlags . NONE , 
209+     traceState, 
210+   } ; 
211+ 
212+   const  ctxWithSpanContext  =  trace . setSpanContext ( ctxWithoutSpan ,  spanContext ) ; 
213+ 
214+   return  ctxWithSpanContext ; 
215+ } 
216+ 
217+ function  getContextForScope ( scope ?: Scope ) : Context  { 
170218  if  ( scope )  { 
171219    const  ctx  =  getContextFromScope ( scope ) ; 
172220    if  ( ctx )  { 
0 commit comments