Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
- Bump `@azure/monitor-opentelemetry-exporter` floor to `1.0.0-beta.43`
- Bump `@opentelemetry/*` core/SDK packages to `2.8.0` / `0.219.0`

### Features Added
- Support multiple isolated SDK instances, each with its own instrumentations, settings, and exporter (e.g. different instrumentations for Azure Monitor vs. A365)

## [1.1.0] - 2026-05-29

### Features Added
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"@microsoft/applicationinsights-web-snippet": "^1.2.3",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.219.0",
"@opentelemetry/context-async-hooks": "^2.8.0",
"@opentelemetry/core": "^2.8.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
"@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
Expand Down
74 changes: 4 additions & 70 deletions src/distro/distro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,85 +53,19 @@ import {
SdkStatsFeature,
} from "../types.js";
import { createInstrumentations, createSampler, createViews } from "./instrumentations.js";
import { _applyA365InstrumentationDefaults } from "./instrumentations.js";
import { Logger } from "../shared/logging/index.js";

// Re-export to preserve the existing import path used by tests/consumers.
export { _applyA365InstrumentationDefaults };

process.env["AZURE_MONITOR_DISTRO_VERSION"] = AZURE_MONITOR_OPENTELEMETRY_VERSION;
process.env["MICROSOFT_OPENTELEMETRY_VERSION"] = MICROSOFT_OPENTELEMETRY_VERSION;

let sdk: NodeSDK;
let disposeAzureMonitor: (() => void) | undefined;
let isShutdown = false;

const A365_DISABLED_INSTRUMENTATIONS_BY_DEFAULT: ReadonlyArray<keyof InstrumentationOptions> = [
"http",
"azureSdk",
"mongoDb",
"mySql",
"postgreSql",
"redis",
"redis4",
"bunyan",
"winston",
];

/**
* Redis and redis4 share the same underlying instrumentation. If a caller
* explicitly configures either key, treat both as explicitly configured so
* the other is not inadvertently disabled.
*/
const REDIS_LINKED_KEYS: ReadonlyArray<keyof InstrumentationOptions> = ["redis", "redis4"];

/**
* When A365 export is enabled, default to GenAI-focused telemetry by disabling
* non-GenAI instrumentations unless callers explicitly configure them.
*
* @internal
*/
export function _applyA365InstrumentationDefaults(
instrumentationOptions: InstrumentationOptions,
userInstrumentationOptions: unknown,
a365Enabled: boolean,
): void {
if (!a365Enabled) {
return;
}

const userOptionsRecord =
userInstrumentationOptions && typeof userInstrumentationOptions === "object"
? (userInstrumentationOptions as Record<string, unknown>)
: undefined;

// Pre-compute whether any Redis-linked key was explicitly configured so
// that configuring `redis4` alone does not inadvertently disable `redis`
// (and vice-versa), which would break the underlying shared instrumentation.
const redisLinkedExplicit =
!!userOptionsRecord &&
REDIS_LINKED_KEYS.some((k) => Object.prototype.hasOwnProperty.call(userOptionsRecord, k));

for (const instrumentationKey of A365_DISABLED_INSTRUMENTATIONS_BY_DEFAULT) {
const isExplicitlyConfigured =
!!userOptionsRecord &&
Object.prototype.hasOwnProperty.call(userOptionsRecord, instrumentationKey);

// Treat redis/redis4 as a linked pair: if either was set by the caller,
// skip disabling both keys.
if (
isExplicitlyConfigured ||
(redisLinkedExplicit &&
REDIS_LINKED_KEYS.includes(instrumentationKey as (typeof REDIS_LINKED_KEYS)[number]))
) {
continue;
}

const currentValue = instrumentationOptions[instrumentationKey];
if (currentValue && typeof currentValue === "object") {
(currentValue as Record<string, unknown>).enabled = false;
} else {
instrumentationOptions[instrumentationKey] = { enabled: false };
}
}
}

/**
* Initialize Microsoft OpenTelemetry.
*
Expand Down
5 changes: 5 additions & 0 deletions src/distro/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ export type {
BrowserSdkLoaderOptions,
A365Options,
} from "./types.js";
export type { MicrosoftOpenTelemetryInstance } from "../types.js";
export { MICROSOFT_OPENTELEMETRY_VERSION } from "./types.js";

export { useMicrosoftOpenTelemetry, shutdownMicrosoftOpenTelemetry } from "./distro.js";
export {
createMicrosoftOpenTelemetryInstance,
runWithMicrosoftOpenTelemetryInstance,
} from "./multiInstance/index.js";
73 changes: 73 additions & 0 deletions src/distro/instrumentations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,83 @@ import type { Instrumentation } from "@opentelemetry/instrumentation";
import type { ViewOptions } from "@opentelemetry/sdk-metrics";

import type { InternalConfig } from "../shared/config.js";
import type { InstrumentationOptions } from "../types.js";
import { ignoreOutgoingRequestHook } from "../azureMonitor/utils/common.js";
import { ApplicationInsightsSampler } from "../azureMonitor/traces/sampler.js";
import { logLevelToSeverityNumber } from "../azureMonitor/utils/logUtils.js";

// ── A365 instrumentation defaults ───────────────────────────────────

const A365_DISABLED_INSTRUMENTATIONS_BY_DEFAULT: ReadonlyArray<keyof InstrumentationOptions> = [
"http",
"azureSdk",
"mongoDb",
"mySql",
"postgreSql",
"redis",
"redis4",
"bunyan",
"winston",
];

/**
* Redis and redis4 share the same underlying instrumentation. If a caller
* explicitly configures either key, treat both as explicitly configured so
* the other is not inadvertently disabled.
*/
const REDIS_LINKED_KEYS: ReadonlyArray<keyof InstrumentationOptions> = ["redis", "redis4"];

/**
* When A365 export is enabled, default to GenAI-focused telemetry by disabling
* non-GenAI instrumentations unless callers explicitly configure them.
*
* @internal
*/
export function _applyA365InstrumentationDefaults(
instrumentationOptions: InstrumentationOptions,
userInstrumentationOptions: unknown,
a365Enabled: boolean,
): void {
if (!a365Enabled) {
return;
}

const userOptionsRecord =
userInstrumentationOptions && typeof userInstrumentationOptions === "object"
? (userInstrumentationOptions as Record<string, unknown>)
: undefined;

// Pre-compute whether any Redis-linked key was explicitly configured so
// that configuring `redis4` alone does not inadvertently disable `redis`
// (and vice-versa), which would break the underlying shared instrumentation.
const redisLinkedExplicit =
!!userOptionsRecord &&
REDIS_LINKED_KEYS.some((k) => Object.prototype.hasOwnProperty.call(userOptionsRecord, k));

for (const instrumentationKey of A365_DISABLED_INSTRUMENTATIONS_BY_DEFAULT) {
const isExplicitlyConfigured =
!!userOptionsRecord &&
Object.prototype.hasOwnProperty.call(userOptionsRecord, instrumentationKey);

// Treat redis/redis4 as a linked pair: if either was set by the caller,
// skip disabling both keys.
if (
isExplicitlyConfigured ||
(redisLinkedExplicit &&
REDIS_LINKED_KEYS.includes(instrumentationKey as (typeof REDIS_LINKED_KEYS)[number]))
) {
continue;
}

const currentValue = instrumentationOptions[instrumentationKey];
if (currentValue && typeof currentValue === "object") {
(currentValue as Record<string, unknown>).enabled = false;
} else {
instrumentationOptions[instrumentationKey] = { enabled: false };
}
}
}

// ── Instrumentations ────────────────────────────────────────────────

/**
Expand Down
Loading
Loading