1- import { trace , type Span , type TracerProvider } from "@opentelemetry/api" ;
1+ import {
2+ trace ,
3+ type Span ,
4+ type Tracer ,
5+ type TracerOptions ,
6+ type TracerProvider ,
7+ } from "@opentelemetry/api" ;
28
39import { Mistral } from "../../../src/index.js" ;
10+ import {
11+ getTelemetryTracer ,
12+ registerTracerProvider ,
13+ } from "../../../src/extra/observability/index.js" ;
414import {
515 configureTelemetry ,
616 configureTelemetryForHook ,
@@ -19,6 +29,8 @@ type FakeProvider = TracerProvider & {
1929 shutdown : ( ) => void ;
2030} ;
2131
32+ type NamedTracer = Tracer & { label : string } ;
33+
2234function createSpan ( ) : Span {
2335 const span = {
2436 spanContext : ( ) => ( { traceId : "" , spanId : "" , traceFlags : 0 } ) ,
@@ -50,6 +62,28 @@ function createProvider(): FakeProvider {
5062 return provider ;
5163}
5264
65+ function createNamedTracer ( label : string ) : NamedTracer {
66+ return {
67+ label,
68+ startSpan : ( ) => createSpan ( ) ,
69+ startActiveSpan : ( ) => undefined as never ,
70+ } as NamedTracer ;
71+ }
72+
73+ function createNamedProvider ( tracer : Tracer ) : TracerProvider {
74+ return {
75+ getTracer : vi . fn ( (
76+ _name : string ,
77+ _version ?: string ,
78+ _options ?: TracerOptions ,
79+ ) => tracer ) ,
80+ } as TracerProvider ;
81+ }
82+
83+ function expectTracerLabel ( tracer : Tracer , label : string ) : void {
84+ expect ( ( tracer as NamedTracer ) . label ) . toBe ( label ) ;
85+ }
86+
5387function createTelemetryModuleLoader ( exporterInstances : Array < { config : unknown } > ) {
5488 return vi . fn ( async ( specifier : string ) => {
5589 if ( specifier === "@opentelemetry/sdk-trace-base" ) {
@@ -140,6 +174,11 @@ async function withEnv<T>(
140174 }
141175}
142176
177+ afterEach ( ( ) => {
178+ registerTracerProvider ( undefined ) ;
179+ vi . restoreAllMocks ( ) ;
180+ } ) ;
181+
143182describe ( "configureTelemetryForHook" , ( ) => {
144183 test ( "defaults to disabled when Mistral telemetry env is absent" , async ( ) => {
145184 await withEnv ( { [ MISTRAL_SDK_TELEMETRY_ENV ] : undefined } , async ( ) => {
@@ -318,6 +357,104 @@ describe("configureTelemetry", () => {
318357
319358 expect ( hook . tracerProvider ) . toBe ( provider ) ;
320359 } ) ;
360+
361+ } ) ;
362+
363+ describe ( "getTelemetryTracer" , ( ) => {
364+ test ( "uses the provider configured on the client" , async ( ) => {
365+ const client = createClient ( ) ;
366+ const clientTracer = createNamedTracer ( "client" ) ;
367+ const registeredTracer = createNamedTracer ( "registered" ) ;
368+ const provider = createNamedProvider ( clientTracer ) ;
369+ const registeredProvider = createNamedProvider ( registeredTracer ) ;
370+ const globalProviderSpy = vi . spyOn ( trace , "getTracerProvider" ) ;
371+ registerTracerProvider ( registeredProvider ) ;
372+
373+ await configureTelemetry ( client , provider ) ;
374+
375+ const tracer = getTelemetryTracer ( client , "my-agent" ) ;
376+
377+ expectTracerLabel ( tracer , "client" ) ;
378+ expect ( provider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , undefined , undefined ) ;
379+ expect ( registeredProvider . getTracer ) . not . toHaveBeenCalled ( ) ;
380+ expect ( globalProviderSpy ) . not . toHaveBeenCalled ( ) ;
381+ } ) ;
382+
383+ test ( "explicit global provider mode bypasses the registered provider" , async ( ) => {
384+ const client = createClient ( ) ;
385+ const registeredTracer = createNamedTracer ( "registered" ) ;
386+ const globalTracer = createNamedTracer ( "global" ) ;
387+ const registeredProvider = createNamedProvider ( registeredTracer ) ;
388+ const globalProvider = createNamedProvider ( globalTracer ) ;
389+ registerTracerProvider ( registeredProvider ) ;
390+ vi . spyOn ( trace , "getTracerProvider" ) . mockReturnValue ( globalProvider ) ;
391+
392+ await configureTelemetry ( client , "global" ) ;
393+
394+ const tracer = getTelemetryTracer ( client , "my-agent" ) ;
395+
396+ expectTracerLabel ( tracer , "global" ) ;
397+ expect ( registeredProvider . getTracer ) . not . toHaveBeenCalled ( ) ;
398+ expect ( globalProvider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , undefined , undefined ) ;
399+ } ) ;
400+
401+ test ( "env global mode bypasses the registered provider before configuration" , async ( ) => {
402+ await withEnv ( { [ MISTRAL_SDK_TELEMETRY_ENV ] : "global" } , async ( ) => {
403+ const client = createClient ( ) ;
404+ const registeredTracer = createNamedTracer ( "registered" ) ;
405+ const globalTracer = createNamedTracer ( "global" ) ;
406+ const registeredProvider = createNamedProvider ( registeredTracer ) ;
407+ const globalProvider = createNamedProvider ( globalTracer ) ;
408+ registerTracerProvider ( registeredProvider ) ;
409+ vi . spyOn ( trace , "getTracerProvider" ) . mockReturnValue ( globalProvider ) ;
410+
411+ const tracer = getTelemetryTracer ( client , "my-agent" ) ;
412+
413+ expectTracerLabel ( tracer , "global" ) ;
414+ expect ( registeredProvider . getTracer ) . not . toHaveBeenCalled ( ) ;
415+ expect ( globalProvider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , undefined , undefined ) ;
416+ } ) ;
417+ } ) ;
418+
419+ test ( "falls back to the registered provider when no client provider is configured" , ( ) => {
420+ const client = createClient ( ) ;
421+ const registeredTracer = createNamedTracer ( "registered" ) ;
422+ const registeredProvider = createNamedProvider ( registeredTracer ) ;
423+ const globalProviderSpy = vi . spyOn ( trace , "getTracerProvider" ) ;
424+ registerTracerProvider ( registeredProvider ) ;
425+
426+ const tracer = getTelemetryTracer ( client , "my-agent" ) ;
427+
428+ expectTracerLabel ( tracer , "registered" ) ;
429+ expect ( registeredProvider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , undefined , undefined ) ;
430+ expect ( globalProviderSpy ) . not . toHaveBeenCalled ( ) ;
431+ } ) ;
432+
433+ test ( "falls back to the global provider when no client or registered provider is configured" , ( ) => {
434+ const client = createClient ( ) ;
435+ const globalTracer = createNamedTracer ( "global" ) ;
436+ const globalProvider = createNamedProvider ( globalTracer ) ;
437+ vi . spyOn ( trace , "getTracerProvider" ) . mockReturnValue ( globalProvider ) ;
438+
439+ const tracer = getTelemetryTracer ( client , "my-agent" ) ;
440+
441+ expectTracerLabel ( tracer , "global" ) ;
442+ expect ( globalProvider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , undefined , undefined ) ;
443+ } ) ;
444+
445+ test ( "passes custom tracer name, version, and options to the selected provider" , async ( ) => {
446+ const client = createClient ( ) ;
447+ const clientTracer = createNamedTracer ( "client" ) ;
448+ const provider = createNamedProvider ( clientTracer ) ;
449+ const options = { schemaUrl : "https://schema.test/v1" } ;
450+
451+ await configureTelemetry ( client , provider ) ;
452+
453+ const tracer = getTelemetryTracer ( client , "my-agent" , "1.2.3" , options ) ;
454+
455+ expectTracerLabel ( tracer , "client" ) ;
456+ expect ( provider . getTracer ) . toHaveBeenCalledWith ( "my-agent" , "1.2.3" , options ) ;
457+ } ) ;
321458} ) ;
322459
323460describe ( "_createTelemetryTracerProvider" , ( ) => {
0 commit comments