From a01231c9ea61fe84981538740d360dea0487206e Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Fri, 26 Sep 2025 18:49:09 -0700 Subject: [PATCH 1/2] Update OTLP detection. --- src/agent/aksLoader.ts | 8 +- test/unitTests/agent/aksLoader.tests.ts | 117 ++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/src/agent/aksLoader.ts b/src/agent/aksLoader.ts index 9c118b82..9e7d5796 100644 --- a/src/agent/aksLoader.ts +++ b/src/agent/aksLoader.ts @@ -58,8 +58,14 @@ export class AKSLoader extends AgentLoader { // Create metricReaders array and add OTLP reader if environment variables request it try { const metricReaders: MetricReader[] = []; + + // Check if OTEL_METRICS_EXPORTER contains "otlp" as a separate value (not as part of another word) + const metricsExporter = process.env.OTEL_METRICS_EXPORTER || ''; + const exportersList = metricsExporter.split(',').map(exp => exp.trim()); + const hasOtlpExporter = exportersList.includes('otlp'); + if ( - process.env.OTEL_METRICS_EXPORTER === "otlp" && + hasOtlpExporter && (process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) ) { try { diff --git a/test/unitTests/agent/aksLoader.tests.ts b/test/unitTests/agent/aksLoader.tests.ts index cc77b282..8bd25136 100644 --- a/test/unitTests/agent/aksLoader.tests.ts +++ b/test/unitTests/agent/aksLoader.tests.ts @@ -212,4 +212,121 @@ describe("agent/AKSLoader", () => { // The protobuf exporter should have different internal structure than the HTTP exporter assert.ok(exporter, "Protobuf exporter should exist"); }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains otlp with other exporters (comma-separated)", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "console,otlp,prometheus", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is included with other exporters"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the metric reader is a PeriodicExportingMetricReader + const metricReader = options.metricReaders[0]; + assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader"); + + // Verify the exporter is an OTLP exporter + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains otlp with spaces", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "console, otlp, prometheus", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is included with spaces"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the exporter is an OTLP exporter + const metricReader = options.metricReaders[0]; + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER has otlp at the beginning", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "otlp,console,prometheus", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is at the beginning"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the exporter is an OTLP exporter + const metricReader = options.metricReaders[0]; + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER has otlp at the end", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "console,prometheus,otlp", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when otlp is at the end"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the exporter is an OTLP exporter + const metricReader = options.metricReaders[0]; + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); + + it("constructor does not create OTLP metric reader when OTEL_METRICS_EXPORTER contains similar strings but not otlp", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "console,otlp-custom,prometheus", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that no metricReaders were added to the options + const options = (agent as any)._options; + 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')"); + }); + + it("constructor does not create OTLP metric reader when OTEL_METRICS_EXPORTER is empty with multiple exporters", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "console,prometheus", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that no metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(!options.metricReaders || options.metricReaders.length === 0, "Should not have any metric readers when otlp is not included in the list"); + }); }); From 15ccce971a9aeb24699a5c04ca3d4a237b9d7c27 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Mon, 29 Sep 2025 12:26:00 -0700 Subject: [PATCH 2/2] Add toLower check. --- src/agent/aksLoader.ts | 4 +-- test/unitTests/agent/aksLoader.tests.ts | 48 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/agent/aksLoader.ts b/src/agent/aksLoader.ts index 9e7d5796..6ee47807 100644 --- a/src/agent/aksLoader.ts +++ b/src/agent/aksLoader.ts @@ -58,9 +58,7 @@ export class AKSLoader extends AgentLoader { // Create metricReaders array and add OTLP reader if environment variables request it try { const metricReaders: MetricReader[] = []; - - // Check if OTEL_METRICS_EXPORTER contains "otlp" as a separate value (not as part of another word) - const metricsExporter = process.env.OTEL_METRICS_EXPORTER || ''; + const metricsExporter = (process.env.OTEL_METRICS_EXPORTER || '').toLowerCase(); const exportersList = metricsExporter.split(',').map(exp => exp.trim()); const hasOtlpExporter = exportersList.includes('otlp'); diff --git a/test/unitTests/agent/aksLoader.tests.ts b/test/unitTests/agent/aksLoader.tests.ts index 8bd25136..a7db3c18 100644 --- a/test/unitTests/agent/aksLoader.tests.ts +++ b/test/unitTests/agent/aksLoader.tests.ts @@ -329,4 +329,52 @@ describe("agent/AKSLoader", () => { const options = (agent as any)._options; assert.ok(!options.metricReaders || options.metricReaders.length === 0, "Should not have any metric readers when otlp is not included in the list"); }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains uppercase OTLP", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "OTLP", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when OTLP is uppercase"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the metric reader is a PeriodicExportingMetricReader + const metricReader = options.metricReaders[0]; + assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader"); + + // Verify the exporter is an OTLP exporter + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); + + it("constructor creates OTLP metric reader when OTEL_METRICS_EXPORTER contains mixed case otlp with other exporters", () => { + const env = { + ["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333", + ["OTEL_METRICS_EXPORTER"]: "CONSOLE,OtLp,PROMETHEUS", + ["OTEL_EXPORTER_OTLP_ENDPOINT"]: "http://localhost:4317" + }; + process.env = env; + + const agent = new AKSLoader(); + + // Verify that metricReaders were added to the options + const options = (agent as any)._options; + assert.ok(options.metricReaders, "metricReaders should be present in options when OtLp is mixed case with other exporters"); + assert.equal(options.metricReaders.length, 1, "Should have exactly one metric reader"); + + // Verify the metric reader is a PeriodicExportingMetricReader + const metricReader = options.metricReaders[0]; + assert.equal(metricReader.constructor.name, "PeriodicExportingMetricReader", "Should be a PeriodicExportingMetricReader"); + + // Verify the exporter is an OTLP exporter + const exporter = (metricReader as any)._exporter; + assert.equal(exporter.constructor.name, "OTLPMetricExporter", "Should be an OTLPMetricExporter"); + }); });