Skip to content

Commit da01c4d

Browse files
authored
Update OTLP Metric Exporter Creation (#1473)
* Update OTLP detection. * Add toLower check.
1 parent 70794fd commit da01c4d

2 files changed

Lines changed: 170 additions & 1 deletion

File tree

src/agent/aksLoader.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,12 @@ export class AKSLoader extends AgentLoader {
5858
// Create metricReaders array and add OTLP reader if environment variables request it
5959
try {
6060
const metricReaders: MetricReader[] = [];
61+
const metricsExporter = (process.env.OTEL_METRICS_EXPORTER || '').toLowerCase();
62+
const exportersList = metricsExporter.split(',').map(exp => exp.trim());
63+
const hasOtlpExporter = exportersList.includes('otlp');
64+
6165
if (
62-
process.env.OTEL_METRICS_EXPORTER === "otlp" &&
66+
hasOtlpExporter &&
6367
(process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT)
6468
) {
6569
try {

test/unitTests/agent/aksLoader.tests.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,169 @@ describe("agent/AKSLoader", () => {
212212
// The protobuf exporter should have different internal structure than the HTTP exporter
213213
assert.ok(exporter, "Protobuf exporter should exist");
214214
});
215+
216+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains otlp with other exporters (comma-separated)", () => {
217+
const env = {
218+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
219+
["OTEL_METRICS_EXPORTER"]: "console,otlp,prometheus",
220+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
221+
};
222+
process.env = env;
223+
224+
const agent = new AKSLoader();
225+
226+
// Verify that metricReaders were added to the options
227+
const options = (agent as any)._options;
228+
assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is included with other exporters");
229+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
230+
231+
// Verify the metric reader is a PeriodicExportingMetricReader
232+
const metricReader = options.metricReaders[0];
233+
assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader");
234+
235+
// Verify the exporter is an OTLP exporter
236+
const exporter = (metricReader as any)._exporter;
237+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
238+
});
239+
240+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains otlp with spaces", () => {
241+
const env = {
242+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
243+
["OTEL_METRICS_EXPORTER"]: "console, otlp, prometheus",
244+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
245+
};
246+
process.env = env;
247+
248+
const agent = new AKSLoader();
249+
250+
// Verify that metricReaders were added to the options
251+
const options = (agent as any)._options;
252+
assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is included with spaces");
253+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
254+
255+
// Verify the exporter is an OTLP exporter
256+
const metricReader = options.metricReaders[0];
257+
const exporter = (metricReader as any)._exporter;
258+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
259+
});
260+
261+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER has otlp at the beginning", () => {
262+
const env = {
263+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
264+
["OTEL_METRICS_EXPORTER"]: "otlp,console,prometheus",
265+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
266+
};
267+
process.env = env;
268+
269+
const agent = new AKSLoader();
270+
271+
// Verify that metricReaders were added to the options
272+
const options = (agent as any)._options;
273+
assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is at the beginning");
274+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
275+
276+
// Verify the exporter is an OTLP exporter
277+
const metricReader = options.metricReaders[0];
278+
const exporter = (metricReader as any)._exporter;
279+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
280+
});
281+
282+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER has otlp at the end", () => {
283+
const env = {
284+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
285+
["OTEL_METRICS_EXPORTER"]: "console,prometheus,otlp",
286+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
287+
};
288+
process.env = env;
289+
290+
const agent = new AKSLoader();
291+
292+
// Verify that metricReaders were added to the options
293+
const options = (agent as any)._options;
294+
assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is at the end");
295+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
296+
297+
// Verify the exporter is an OTLP exporter
298+
const metricReader = options.metricReaders[0];
299+
const exporter = (metricReader as any)._exporter;
300+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
301+
});
302+
303+
it("constructor does not create OTLP metric reader when OTEL_METRICS_EXPORTER contains similar strings but not otlp", () => {
304+
const env = {
305+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
306+
["OTEL_METRICS_EXPORTER"]: "console,otlp-custom,prometheus",
307+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
308+
};
309+
process.env = env;
310+
311+
const agent = new AKSLoader();
312+
313+
// Verify that no metricReaders were added to the options
314+
const options = (agent as any)._options;
315+
assert.ok(!options.metricReaders || options.metricReaders.length === 0, "Should not have any metric readers when 'otlp' is not exactly present (only similar strings like 'otlp-custom')");
316+
});
317+
318+
it("constructor does not create OTLP metric reader when OTEL_METRICS_EXPORTER is empty with multiple exporters", () => {
319+
const env = {
320+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
321+
["OTEL_METRICS_EXPORTER"]: "console,prometheus",
322+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
323+
};
324+
process.env = env;
325+
326+
const agent = new AKSLoader();
327+
328+
// Verify that no metricReaders were added to the options
329+
const options = (agent as any)._options;
330+
assert.ok(!options.metricReaders || options.metricReaders.length === 0, "Should not have any metric readers when otlp is not included in the list");
331+
});
332+
333+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains uppercase OTLP", () => {
334+
const env = {
335+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
336+
["OTEL_METRICS_EXPORTER"]: "OTLP",
337+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
338+
};
339+
process.env = env;
340+
341+
const agent = new AKSLoader();
342+
343+
// Verify that metricReaders were added to the options
344+
const options = (agent as any)._options;
345+
assert.ok(options.metricReaders, "metricReaders should be present in options when OTLP is uppercase");
346+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
347+
348+
// Verify the metric reader is a PeriodicExportingMetricReader
349+
const metricReader = options.metricReaders[0];
350+
assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader");
351+
352+
// Verify the exporter is an OTLP exporter
353+
const exporter = (metricReader as any)._exporter;
354+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
355+
});
356+
357+
it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains mixed case otlp with other exporters", () => {
358+
const env = {
359+
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
360+
["OTEL_METRICS_EXPORTER"]: "CONSOLE,OtLp,PROMETHEUS",
361+
["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317"
362+
};
363+
process.env = env;
364+
365+
const agent = new AKSLoader();
366+
367+
// Verify that metricReaders were added to the options
368+
const options = (agent as any)._options;
369+
assert.ok(options.metricReaders, "metricReaders should be present in options when OtLp is mixed case with other exporters");
370+
assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader");
371+
372+
// Verify the metric reader is a PeriodicExportingMetricReader
373+
const metricReader = options.metricReaders[0];
374+
assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader");
375+
376+
// Verify the exporter is an OTLP exporter
377+
const exporter = (metricReader as any)._exporter;
378+
assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter");
379+
});
215380
});

0 commit comments

Comments
 (0)