@@ -97,30 +97,39 @@ function installTestAsyncContextStrategy(): void {
9797 } ) ;
9898}
9999
100- /** Drives a channel's `tracePromise` and captures the span bound by the subscriber. */
100+ /**
101+ * Drives a channel's `tracePromise` inside an enclosing span and captures the span bound by the
102+ * subscriber. The subscriber only creates a span when there is an enclosing active span, so the
103+ * helper always establishes one and returns its id for parenting assertions.
104+ */
101105async function traceOperation (
102106 channelName : string ,
103107 data : Record < string , unknown > ,
104108 outcome : { result ?: unknown ; error ?: Error } ,
105- ) : Promise < { span : Span | undefined ; childParentSpanId : string | undefined } > {
109+ ) : Promise < { span : Span | undefined ; childParentSpanId : string | undefined ; enclosingSpanId : string | undefined } > {
106110 const channel = tracingChannel ( channelName ) ;
107111 let span : Span | undefined ;
108112 let childParentSpanId : string | undefined ;
113+ let enclosingSpanId : string | undefined ;
109114
110- const run = channel . tracePromise ( async ( ) => {
111- span = getActiveSpan ( ) ;
112- startSpan ( { name : 'child' } , child => {
113- childParentSpanId = spanToJSON ( child ) . parent_span_id ;
114- } ) ;
115- if ( outcome . error ) {
116- throw outcome . error ;
117- }
118- return outcome . result ;
119- } , data ) ;
115+ await startSpan ( { name : 'enclosing' } , async enclosing => {
116+ enclosingSpanId = enclosing . spanContext ( ) . spanId ;
117+
118+ const run = channel . tracePromise ( async ( ) => {
119+ span = getActiveSpan ( ) ;
120+ startSpan ( { name : 'child' } , child => {
121+ childParentSpanId = spanToJSON ( child ) . parent_span_id ;
122+ } ) ;
123+ if ( outcome . error ) {
124+ throw outcome . error ;
125+ }
126+ return outcome . result ;
127+ } , data ) ;
120128
121- await run . catch ( ( ) => undefined ) ;
129+ await run . catch ( ( ) => undefined ) ;
130+ } ) ;
122131
123- return { span, childParentSpanId } ;
132+ return { span, childParentSpanId, enclosingSpanId } ;
124133}
125134
126135const factory = tracingChannel as MySQL2TracingChannelFactory ;
@@ -153,6 +162,20 @@ describe('subscribeMysql2DiagnosticChannels', () => {
153162 vi . clearAllMocks ( ) ;
154163 } ) ;
155164
165+ it ( 'does not create a span when there is no enclosing active span' , async ( ) => {
166+ const channel = tracingChannel ( MYSQL2_DC_CHANNEL_QUERY ) ;
167+ let span : Span | undefined ;
168+
169+ await channel . tracePromise (
170+ async ( ) => {
171+ span = getActiveSpan ( ) ;
172+ } ,
173+ { query : 'SELECT 1' } ,
174+ ) ;
175+
176+ expect ( span ) . toBeUndefined ( ) ;
177+ } ) ;
178+
156179 describe ( 'query channel' , ( ) => {
157180 it ( 'creates a db span with stable semconv attributes' , async ( ) => {
158181 const { span } = await traceOperation (
@@ -219,16 +242,14 @@ describe('subscribeMysql2DiagnosticChannels', () => {
219242 } ) ;
220243
221244 it ( 'parents the mysql2 span to the surrounding span and parents children to it' , async ( ) => {
222- let outerSpanId : string | undefined ;
223- let result : Awaited < ReturnType < typeof traceOperation > > | undefined ;
224-
225- await startSpan ( { name : 'outer' } , async outer => {
226- outerSpanId = outer . spanContext ( ) . spanId ;
227- result = await traceOperation ( MYSQL2_DC_CHANNEL_QUERY , { query : 'SELECT 1' } , { result : [ ] } ) ;
228- } ) ;
245+ const { span, childParentSpanId, enclosingSpanId } = await traceOperation (
246+ MYSQL2_DC_CHANNEL_QUERY ,
247+ { query : 'SELECT 1' } ,
248+ { result : [ ] } ,
249+ ) ;
229250
230- expect ( spanToJSON ( result ! . span ! ) . parent_span_id ) . toBe ( outerSpanId ) ;
231- expect ( result ! . childParentSpanId ) . toBe ( result ! . span ! . spanContext ( ) . spanId ) ;
251+ expect ( spanToJSON ( span ! ) . parent_span_id ) . toBe ( enclosingSpanId ) ;
252+ expect ( childParentSpanId ) . toBe ( span ! . spanContext ( ) . spanId ) ;
232253 } ) ;
233254 } ) ;
234255
0 commit comments