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