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