1- import { TraceFlags , context , trace } from '@opentelemetry/api' ;
1+ import { SpanContext , TraceFlags , context , trace } from '@opentelemetry/api' ;
22import type { SpanProcessor } from '@opentelemetry/sdk-trace-base' ;
33import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , addBreadcrumb , getClient , setTag , withIsolationScope } from '@sentry/core' ;
4- import type { PropagationContext , TransactionEvent } from '@sentry/types' ;
4+ import type { Event , PropagationContext , TransactionEvent } from '@sentry/types' ;
55import { logger } from '@sentry/utils' ;
66
7+ import { TraceState } from '@opentelemetry/core' ;
78import { spanToJSON } from '@sentry/core' ;
9+ import { SENTRY_TRACE_STATE_DSC } from '../../src/constants' ;
810import { SentrySpanProcessor } from '../../src/spanProcessor' ;
911import { startInactiveSpan , startSpan } from '../../src/trace' ;
1012import { setPropagationContextOnContext } from '../../src/utils/contextData' ;
@@ -14,6 +16,7 @@ import { cleanupOtel, getProvider, mockSdkInit } from '../helpers/mockSdkInit';
1416describe ( 'Integration | Transactions' , ( ) => {
1517 afterEach ( ( ) => {
1618 jest . restoreAllMocks ( ) ;
19+ jest . useRealTimers ( ) ;
1720 cleanupOtel ( ) ;
1821 } ) ;
1922
@@ -515,4 +518,68 @@ describe('Integration | Transactions', () => {
515518 ] ) ,
516519 ) ;
517520 } ) ;
521+
522+ it ( 'uses & inherits DSC on span trace state' , async ( ) => {
523+ const transactionEvents : Event [ ] = [ ] ;
524+ const beforeSendTransaction = jest . fn ( event => {
525+ transactionEvents . push ( event ) ;
526+ return null ;
527+ } ) ;
528+
529+ const traceId = 'd4cda95b652f4a1592b449d5929fda1b' ;
530+ const parentSpanId = '6e0c63257de34c92' ;
531+
532+ const dscString = `sentry-transaction=other-transaction,sentry-environment=other,sentry-release=8.0.0,sentry-public_key=public,sentry-trace_id=${ traceId } ,sentry-sampled=true` ;
533+
534+ const spanContext : SpanContext = {
535+ traceId,
536+ spanId : parentSpanId ,
537+ isRemote : true ,
538+ traceFlags : TraceFlags . SAMPLED ,
539+ traceState : new TraceState ( ) . set ( SENTRY_TRACE_STATE_DSC , dscString ) ,
540+ } ;
541+
542+ const propagationContext : PropagationContext = {
543+ traceId,
544+ parentSpanId,
545+ spanId : '6e0c63257de34c93' ,
546+ sampled : true ,
547+ } ;
548+
549+ mockSdkInit ( { enableTracing : true , beforeSendTransaction } ) ;
550+
551+ const client = getClient ( ) as TestClientInterface ;
552+
553+ // We simulate the correct context we'd normally get from the SentryPropagator
554+ context . with (
555+ trace . setSpanContext ( setPropagationContextOnContext ( context . active ( ) , propagationContext ) , spanContext ) ,
556+ ( ) => {
557+ startSpan ( { op : 'test op' , name : 'test name' , source : 'task' , origin : 'auto.test' } , span => {
558+ expect ( span . spanContext ( ) . traceState ?. get ( SENTRY_TRACE_STATE_DSC ) ) . toEqual ( dscString ) ;
559+
560+ const subSpan = startInactiveSpan ( { name : 'inner span 1' } ) ;
561+
562+ expect ( subSpan . spanContext ( ) . traceState ?. get ( SENTRY_TRACE_STATE_DSC ) ) . toEqual ( dscString ) ;
563+
564+ subSpan . end ( ) ;
565+
566+ startSpan ( { name : 'inner span 2' } , subSpan => {
567+ expect ( subSpan . spanContext ( ) . traceState ?. get ( SENTRY_TRACE_STATE_DSC ) ) . toEqual ( dscString ) ;
568+ } ) ;
569+ } ) ;
570+ } ,
571+ ) ;
572+
573+ await client . flush ( ) ;
574+
575+ expect ( transactionEvents ) . toHaveLength ( 1 ) ;
576+ expect ( transactionEvents [ 0 ] ?. sdkProcessingMetadata ?. dynamicSamplingContext ) . toEqual ( {
577+ environment : 'other' ,
578+ public_key : 'public' ,
579+ release : '8.0.0' ,
580+ sampled : 'true' ,
581+ trace_id : traceId ,
582+ transaction : 'other-transaction' ,
583+ } ) ;
584+ } ) ;
518585} ) ;
0 commit comments