@@ -60,4 +60,127 @@ describe("agent/AKSLoader", () => {
6060 let loggerProvider = logs . getLoggerProvider ( ) as any ;
6161 assert . equal ( loggerProvider . constructor . name , "LoggerProvider" ) ;
6262 } ) ;
63+
64+ it ( "constructor creates OTLP metric reader when environment variables are set" , ( ) => {
65+ const env = {
66+ [ "APPLICATIONINSIGHTS_CONNECTION_STRING" ] : "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333" ,
67+ [ "OTEL_METRICS_EXPORTER" ] : "otlp" ,
68+ [ "OTEL_EXPORTER_OTLP_ENDPOINT" ] : "http://localhost:4317"
69+ } ;
70+ process . env = env ;
71+
72+ const agent = new AKSLoader ( ) ;
73+
74+ // Verify that metricReaders were added to the options
75+ const options = ( agent as any ) . _options ;
76+ assert . ok ( options . metricReaders , "metricReaders should be present in options" ) ;
77+ assert . equal ( options . metricReaders . length , 1 , "Should have exactly one metric reader" ) ;
78+
79+ // Verify the metric reader is a PeriodicExportingMetricReader
80+ const metricReader = options . metricReaders [ 0 ] ;
81+ assert . equal ( metricReader . constructor . name , "PeriodicExportingMetricReader" , "Should be a PeriodicExportingMetricReader" ) ;
82+
83+ // Verify the exporter is an OTLP exporter
84+ const exporter = ( metricReader as any ) . _exporter ;
85+ assert . equal ( exporter . constructor . name , "OTLPMetricExporter" , "Should be an OTLPMetricExporter" ) ;
86+
87+ // Check that the URL is configured in parameters
88+ const delegate = ( exporter as any ) . _delegate ;
89+ const transport = delegate . _transport ;
90+ const innerTransport = transport . _transport ;
91+ const parameters = innerTransport . _parameters ;
92+
93+ const url = parameters . url || parameters . endpoint ;
94+ assert . ok ( url , "Parameters should have a URL configured" ) ;
95+ assert . equal ( url . replace ( / \/ $ / , "" ) , "http://localhost:4317/v1/metrics" , "Should use the base OTLP endpoint URL" ) ;
96+
97+ // Verify the exporter type
98+ assert . ok ( exporter , "Exporter should exist" ) ;
99+ assert . equal ( exporter . constructor . name , "OTLPMetricExporter" , "Should be an OTLPMetricExporter" ) ;
100+ } ) ;
101+
102+ it ( "constructor creates OTLP metric reader with metrics-specific endpoint" , ( ) => {
103+ const env = {
104+ [ "APPLICATIONINSIGHTS_CONNECTION_STRING" ] : "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333" ,
105+ [ "OTEL_METRICS_EXPORTER" ] : "otlp" ,
106+ [ "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" ] : "http://localhost:4318/v1/metrics"
107+ } ;
108+ process . env = env ;
109+
110+ const agent = new AKSLoader ( ) ;
111+
112+ // Verify that metricReaders were added to the options
113+ const options = ( agent as any ) . _options ;
114+ assert . ok ( options . metricReaders , "metricReaders should be present in options" ) ;
115+ assert . equal ( options . metricReaders . length , 1 , "Should have exactly one metric reader" ) ;
116+
117+ // Verify the exporter URL uses the metrics-specific endpoint
118+ const metricReader = options . metricReaders [ 0 ] ;
119+ const exporter = ( metricReader as any ) . _exporter ;
120+
121+ // Check the configured URL in the transport parameters
122+ const delegate = ( exporter as any ) . _delegate ;
123+ const transport = delegate . _transport ;
124+ const innerTransport = transport . _transport ;
125+ const parameters = innerTransport . _parameters ;
126+
127+ const url = parameters . url || parameters . endpoint ;
128+ assert . ok ( url , "Exporter should have a URL configured" ) ;
129+ assert . equal ( url , "http://localhost:4318/v1/metrics" , "Should use the metrics-specific OTLP endpoint URL" ) ;
130+ } ) ;
131+
132+ it ( "constructor does not create OTLP metric reader when OTEL_METRICS_EXPORTER is not otlp" , ( ) => {
133+ const env = {
134+ [ "APPLICATIONINSIGHTS_CONNECTION_STRING" ] : "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333" ,
135+ [ "OTEL_METRICS_EXPORTER" ] : "console" ,
136+ [ "OTEL_EXPORTER_OTLP_ENDPOINT" ] : "http://localhost:4317"
137+ } ;
138+ process . env = env ;
139+
140+ const agent = new AKSLoader ( ) ;
141+
142+ // Verify that no metricReaders were added to the options
143+ const options = ( agent as any ) . _options ;
144+ assert . ok ( ! options . metricReaders || options . metricReaders . length === 0 , "Should not have any metric readers when OTEL_METRICS_EXPORTER is not 'otlp'" ) ;
145+ } ) ;
146+
147+ it ( "constructor does not create OTLP metric reader when no endpoint is provided" , ( ) => {
148+ const env = {
149+ [ "APPLICATIONINSIGHTS_CONNECTION_STRING" ] : "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333" ,
150+ [ "OTEL_METRICS_EXPORTER" ] : "otlp"
151+ // No OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
152+ } ;
153+ process . env = env ;
154+
155+ const agent = new AKSLoader ( ) ;
156+
157+ // Verify that no metricReaders were added to the options
158+ const options = ( agent as any ) . _options ;
159+ assert . ok ( ! options . metricReaders || options . metricReaders . length === 0 , "Should not have any metric readers when no OTLP endpoint is provided" ) ;
160+ } ) ;
161+
162+ it ( "initialize with OTLP metric reader creates multiple metric collectors" , ( ) => {
163+ const env = {
164+ [ "APPLICATIONINSIGHTS_CONNECTION_STRING" ] : "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333" ,
165+ [ "OTEL_METRICS_EXPORTER" ] : "otlp" ,
166+ [ "OTEL_EXPORTER_OTLP_ENDPOINT" ] : "http://localhost:4317"
167+ } ;
168+ process . env = env ;
169+
170+ const agent = new AKSLoader ( ) ;
171+ agent . initialize ( ) ;
172+
173+ let meterProvider = metrics . getMeterProvider ( ) as any ;
174+ assert . equal ( meterProvider . constructor . name , "MeterProvider" ) ;
175+
176+ // Should have both Azure Monitor and OTLP metric readers
177+ const metricCollectors = meterProvider [ "_sharedState" ] [ "metricCollectors" ] ;
178+ assert . ok ( metricCollectors . length >= 1 , "Should have at least one metric collector (Azure Monitor)" ) ;
179+
180+ // Check that we have at least one Azure Monitor exporter
181+ const azureMonitorExporters = metricCollectors . filter ( ( collector : any ) =>
182+ collector [ "_metricReader" ] [ "_exporter" ] . constructor . name === "AzureMonitorMetricExporter"
183+ ) ;
184+ assert . equal ( azureMonitorExporters . length , 1 , "Should have exactly one Azure Monitor metric exporter" ) ;
185+ } ) ;
63186} ) ;
0 commit comments