Skip to content

Commit 7cd27dd

Browse files
authored
[Monitor OpenTelemetry Exporter] Add KUBERNETES_SERVICE_HOST Detection (#36660)
### Packages impacted by this PR @azure/monitor-opentelemetry-exporter ### Describe the problem that is addressed by this PR This pull request improves AKS (Azure Kubernetes Service) detection in the `monitor-opentelemetry-exporter` package by updating the logic to recognize AKS environments when the `KUBERNETES_SERVICE_HOST` environment variable is present. This change helps ensure that the exporter correctly identifies AKS deployments even if `AKS_ARM_NAMESPACE_ID` is not set. **AKS detection improvements:** * Updated `StatsbeatMetrics#getResourceProvider` in `statsbeatMetrics.ts` to detect AKS when either `AKS_ARM_NAMESPACE_ID` or `KUBERNETES_SERVICE_HOST` is defined, and set the resource identifier accordingly. * Documented the AKS detection enhancement in the `CHANGELOG.md` for the upcoming `1.0.0-beta.37` release. ### What are the possible designs available to address the problem? If there are more than one possible design, why was the one in this PR chosen? ### Checklists - [x] Added impacted package name to the issue description - [ ] Does this PR needs any fixes in the SDK Generator?** _(If so, create an Issue in the [Autorest/typescript](https://github.com/Azure/autorest.typescript) repository and link it here)_ - [x] Added a changelog (if necessary)
1 parent 66dad41 commit 7cd27dd

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

sdk/monitor/monitor-opentelemetry-exporter/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Release History
22

3+
### 1.0.0-beta.37 ()
4+
5+
### Features Added
6+
7+
### Bugs Fixed
8+
9+
### Breaking Changes
10+
11+
### Other Changes
12+
13+
- Detect AKS when the `KUBERNETES_SERVICE_HOST` environment variable is defined.
14+
315
## 1.0.0-beta.36 (2025-11-10)
416

517
### Bugs Fixed

sdk/monitor/monitor-opentelemetry-exporter/src/export/statsbeat/statsbeatMetrics.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ export class StatsbeatMetrics {
2525
protected async getResourceProvider(): Promise<void> {
2626
// Check resource provider
2727
this.resourceProvider = StatsbeatResourceProvider.unknown;
28-
if (process.env.AKS_ARM_NAMESPACE_ID) {
28+
if (process.env.AKS_ARM_NAMESPACE_ID || process.env.KUBERNETES_SERVICE_HOST) {
2929
// AKS
3030
this.resourceProvider = StatsbeatResourceProvider.aks;
31-
this.resourceIdentifier = process.env.AKS_ARM_NAMESPACE_ID;
31+
this.resourceIdentifier =
32+
process.env.AKS_ARM_NAMESPACE_ID || process.env.KUBERNETES_SERVICE_HOST || "";
3233
} else if (process.env.WEBSITE_SITE_NAME && !process.env.FUNCTIONS_WORKER_RUNTIME) {
3334
// Web apps
3435
this.resourceProvider = StatsbeatResourceProvider.appsvc;

sdk/monitor/monitor-opentelemetry-exporter/test/internal/statsbeat.spec.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ describe("#AzureMonitorStatsbeatExporter", () => {
292292
assert.strictEqual(statsbeat["resourceIdentifier"], "undefined/undefined");
293293
});
294294

295-
it("should determine if the rp is AKS", async () => {
295+
it("should determine if the rp is AKS with AKS_ARM_NAMESPACE_ID", async () => {
296296
const newEnv = <{ [id: string]: string }>{};
297297
newEnv["AKS_ARM_NAMESPACE_ID"] = "testaks";
298298
const originalEnv = process.env;
@@ -304,6 +304,31 @@ describe("#AzureMonitorStatsbeatExporter", () => {
304304
assert.strictEqual(statsbeat["resourceIdentifier"], "testaks");
305305
});
306306

307+
it("should determine if the rp is AKS with KUBERNETES_SERVICE_HOST", async () => {
308+
const newEnv = <{ [id: string]: string }>{};
309+
newEnv["KUBERNETES_SERVICE_HOST"] = "10.0.0.1";
310+
const originalEnv = process.env;
311+
process.env = newEnv;
312+
313+
await statsbeat["getResourceProvider"]();
314+
process.env = originalEnv;
315+
assert.strictEqual(statsbeat["resourceProvider"], "aks");
316+
assert.strictEqual(statsbeat["resourceIdentifier"], "10.0.0.1");
317+
});
318+
319+
it("should prioritize AKS_ARM_NAMESPACE_ID over KUBERNETES_SERVICE_HOST when both are present", async () => {
320+
const newEnv = <{ [id: string]: string }>{};
321+
newEnv["AKS_ARM_NAMESPACE_ID"] = "testaks";
322+
newEnv["KUBERNETES_SERVICE_HOST"] = "10.0.0.1";
323+
const originalEnv = process.env;
324+
process.env = newEnv;
325+
326+
await statsbeat["getResourceProvider"]();
327+
process.env = originalEnv;
328+
assert.strictEqual(statsbeat["resourceProvider"], "aks");
329+
assert.strictEqual(statsbeat["resourceIdentifier"], "testaks");
330+
});
331+
307332
it("should override OS and VM info", async () => {
308333
const getAzureComputeStub = vi.spyOn(statsbeat, "getAzureComputeMetadata");
309334
getAzureComputeStub.mockResolvedValue(true);
@@ -459,7 +484,7 @@ describe("#AzureMonitorStatsbeatExporter", () => {
459484
});
460485

461486
describe("Priority and edge cases", () => {
462-
it("should prioritize AKS detection over App Service", async () => {
487+
it("should prioritize AKS detection with AKS_ARM_NAMESPACE_ID over App Service", async () => {
463488
const newEnv = <{ [id: string]: string }>{};
464489
newEnv["AKS_ARM_NAMESPACE_ID"] =
465490
"/subscriptions/test/resourceGroups/test/providers/Microsoft.ContainerService/managedClusters/test-aks";
@@ -477,6 +502,36 @@ describe("#AzureMonitorStatsbeatExporter", () => {
477502
);
478503
});
479504

505+
it("should prioritize AKS detection with KUBERNETES_SERVICE_HOST over App Service", async () => {
506+
const newEnv = <{ [id: string]: string }>{};
507+
newEnv["KUBERNETES_SERVICE_HOST"] = "10.0.0.1";
508+
newEnv["WEBSITE_SITE_NAME"] = "my-webapp";
509+
const originalEnv = process.env;
510+
process.env = newEnv;
511+
512+
await statsbeat["getResourceProvider"]();
513+
514+
process.env = originalEnv;
515+
assert.strictEqual(statsbeat["resourceProvider"], "aks");
516+
assert.strictEqual(statsbeat["resourceIdentifier"], "10.0.0.1");
517+
});
518+
519+
it("should prioritize AKS detection with KUBERNETES_SERVICE_HOST over Functions", async () => {
520+
const newEnv = <{ [id: string]: string }>{};
521+
newEnv["KUBERNETES_SERVICE_HOST"] = "10.0.0.1";
522+
newEnv["WEBSITE_SITE_NAME"] = "my-function-app";
523+
newEnv["FUNCTIONS_WORKER_RUNTIME"] = "node";
524+
newEnv["WEBSITE_HOSTNAME"] = "my-function-app.azurewebsites.net";
525+
const originalEnv = process.env;
526+
process.env = newEnv;
527+
528+
await statsbeat["getResourceProvider"]();
529+
530+
process.env = originalEnv;
531+
assert.strictEqual(statsbeat["resourceProvider"], "aks");
532+
assert.strictEqual(statsbeat["resourceIdentifier"], "10.0.0.1");
533+
});
534+
480535
it("should prioritize Functions detection over App Service when both conditions are met", async () => {
481536
const newEnv = <{ [id: string]: string }>{};
482537
newEnv["WEBSITE_SITE_NAME"] = "my-function-app";

0 commit comments

Comments
 (0)