1
+ import type { SpanContext } from '@opentelemetry/api' ;
1
2
import { TraceFlags , context , trace } from '@opentelemetry/api' ;
2
3
import type { SpanProcessor } from '@opentelemetry/sdk-trace-base' ;
3
4
import { 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' ;
5
6
import { logger } from '@sentry/utils' ;
6
7
8
+ import { TraceState } from '@opentelemetry/core' ;
7
9
import { spanToJSON } from '@sentry/core' ;
10
+ import { SENTRY_TRACE_STATE_DSC } from '../../src/constants' ;
8
11
import { SentrySpanProcessor } from '../../src/spanProcessor' ;
9
12
import { startInactiveSpan , startSpan } from '../../src/trace' ;
10
13
import { setPropagationContextOnContext } from '../../src/utils/contextData' ;
@@ -14,6 +17,7 @@ import { cleanupOtel, getProvider, mockSdkInit } from '../helpers/mockSdkInit';
14
17
describe ( 'Integration | Transactions' , ( ) => {
15
18
afterEach ( ( ) => {
16
19
jest . restoreAllMocks ( ) ;
20
+ jest . useRealTimers ( ) ;
17
21
cleanupOtel ( ) ;
18
22
} ) ;
19
23
@@ -515,4 +519,68 @@ describe('Integration | Transactions', () => {
515
519
] ) ,
516
520
) ;
517
521
} ) ;
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
+ } ) ;
518
586
} ) ;
0 commit comments