@@ -4,12 +4,16 @@ import { Resource } from '@opentelemetry/resources';
44import { Span as OtelSpan } from '@opentelemetry/sdk-trace-base' ;
55import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node' ;
66import { SemanticAttributes , SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' ;
7- import { Hub , makeMain } from '@sentry/core' ;
7+ import { createTransport , Hub , makeMain } from '@sentry/core' ;
8+ import { NodeClient } from '@sentry/node' ;
89import { addExtensionMethods , Span as SentrySpan , SpanStatusType , Transaction } from '@sentry/tracing' ;
910import { Contexts , Scope } from '@sentry/types' ;
11+ import { resolvedSyncPromise } from '@sentry/utils' ;
1012
1113import { SENTRY_SPAN_PROCESSOR_MAP , SentrySpanProcessor } from '../src/spanprocessor' ;
1214
15+ const SENTRY_DSN = 'https://[email protected] /0' ; 16+
1317// Integration Test of SentrySpanProcessor
1418
1519beforeAll ( ( ) => {
@@ -22,7 +26,13 @@ describe('SentrySpanProcessor', () => {
2226 let spanProcessor : SentrySpanProcessor ;
2327
2428 beforeEach ( ( ) => {
25- hub = new Hub ( ) ;
29+ const client = new NodeClient ( {
30+ dsn : SENTRY_DSN ,
31+ integrations : [ ] ,
32+ transport : ( ) => createTransport ( { recordDroppedEvent : ( ) => undefined } , _ => resolvedSyncPromise ( { } ) ) ,
33+ stackParser : ( ) => [ ] ,
34+ } ) ;
35+ hub = new Hub ( client ) ;
2636 makeMain ( hub ) ;
2737
2838 spanProcessor = new SentrySpanProcessor ( ) ;
@@ -561,6 +571,106 @@ describe('SentrySpanProcessor', () => {
561571 } ) ;
562572 } ) ;
563573 } ) ;
574+
575+ describe ( 'skip sentry requests' , ( ) => {
576+ it ( 'does not finish transaction for Sentry request' , async ( ) => {
577+ const otelSpan = provider . getTracer ( 'default' ) . startSpan ( 'POST to sentry' , {
578+ attributes : {
579+ [ SemanticAttributes . HTTP_METHOD ] : 'POST' ,
580+ [ SemanticAttributes . HTTP_URL ] : `${ SENTRY_DSN } /sub/route` ,
581+ } ,
582+ } ) as OtelSpan ;
583+
584+ const sentrySpanTransaction = getSpanForOtelSpan ( otelSpan ) as Transaction | undefined ;
585+ expect ( sentrySpanTransaction ) . toBeDefined ( ) ;
586+
587+ otelSpan . end ( ) ;
588+
589+ expect ( sentrySpanTransaction ?. endTimestamp ) . toBeUndefined ( ) ;
590+
591+ // Ensure it is still removed from map!
592+ expect ( getSpanForOtelSpan ( otelSpan ) ) . toBeUndefined ( ) ;
593+ } ) ;
594+
595+ it ( 'finishes transaction for non-Sentry request' , async ( ) => {
596+ const otelSpan = provider . getTracer ( 'default' ) . startSpan ( 'POST to sentry' , {
597+ attributes : {
598+ [ SemanticAttributes . HTTP_METHOD ] : 'POST' ,
599+ [ SemanticAttributes . HTTP_URL ] : 'https://other.sentry.io/sub/route' ,
600+ } ,
601+ } ) as OtelSpan ;
602+
603+ const sentrySpanTransaction = getSpanForOtelSpan ( otelSpan ) as Transaction | undefined ;
604+ expect ( sentrySpanTransaction ) . toBeDefined ( ) ;
605+
606+ otelSpan . end ( ) ;
607+
608+ expect ( sentrySpanTransaction ?. endTimestamp ) . toBeDefined ( ) ;
609+ } ) ;
610+
611+ it ( 'does not finish spans for Sentry request' , async ( ) => {
612+ const tracer = provider . getTracer ( 'default' ) ;
613+
614+ tracer . startActiveSpan ( 'GET /users' , ( ) => {
615+ tracer . startActiveSpan (
616+ 'SELECT * FROM users;' ,
617+ {
618+ attributes : {
619+ [ SemanticAttributes . HTTP_METHOD ] : 'POST' ,
620+ [ SemanticAttributes . HTTP_URL ] : `${ SENTRY_DSN } /sub/route` ,
621+ } ,
622+ } ,
623+ child => {
624+ const childOtelSpan = child as OtelSpan ;
625+
626+ const sentrySpan = getSpanForOtelSpan ( childOtelSpan ) ;
627+ expect ( sentrySpan ) . toBeDefined ( ) ;
628+
629+ childOtelSpan . end ( ) ;
630+
631+ expect ( sentrySpan ?. endTimestamp ) . toBeUndefined ( ) ;
632+
633+ // Ensure it is still removed from map!
634+ expect ( getSpanForOtelSpan ( childOtelSpan ) ) . toBeUndefined ( ) ;
635+ } ,
636+ ) ;
637+ } ) ;
638+ } ) ;
639+
640+ it ( 'handles child spans of Sentry requests normally' , async ( ) => {
641+ const tracer = provider . getTracer ( 'default' ) ;
642+
643+ tracer . startActiveSpan ( 'GET /users' , ( ) => {
644+ tracer . startActiveSpan (
645+ 'SELECT * FROM users;' ,
646+ {
647+ attributes : {
648+ [ SemanticAttributes . HTTP_METHOD ] : 'POST' ,
649+ [ SemanticAttributes . HTTP_URL ] : `${ SENTRY_DSN } /sub/route` ,
650+ } ,
651+ } ,
652+ child => {
653+ const childOtelSpan = child as OtelSpan ;
654+
655+ const grandchildSpan = tracer . startSpan ( 'child 1' ) ;
656+
657+ const sentrySpan = getSpanForOtelSpan ( childOtelSpan ) ;
658+ expect ( sentrySpan ) . toBeDefined ( ) ;
659+
660+ const sentryGrandchildSpan = getSpanForOtelSpan ( grandchildSpan ) ;
661+ expect ( sentryGrandchildSpan ) . toBeDefined ( ) ;
662+
663+ grandchildSpan . end ( ) ;
664+
665+ childOtelSpan . end ( ) ;
666+
667+ expect ( sentryGrandchildSpan ?. endTimestamp ) . toBeDefined ( ) ;
668+ expect ( sentrySpan ?. endTimestamp ) . toBeUndefined ( ) ;
669+ } ,
670+ ) ;
671+ } ) ;
672+ } ) ;
673+ } ) ;
564674} ) ;
565675
566676// OTEL expects a custom date format
0 commit comments