Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release History

### 3.13.1 ()

#### Other Changes

- Update OTel global detection to wait for the customer app to initialize before detection.

### 3.13.0 (2026-01-16)

#### Other Changes
Expand Down
9 changes: 7 additions & 2 deletions src/agent/agentLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useAzureMonitor } from "../main";


const forceStart = process.env.APPLICATIONINSIGHTS_FORCE_START === "true";
const OTEL_DETECTION_DELAY_MS = 60000; // 1 minute
// Azure Connection String
const ENV_connectionString = "APPLICATIONINSIGHTS_CONNECTION_STRING";
const ENV_AZURE_PREFIX = "APPSETTING_"; // Azure adds this prefix to all environment variables
Expand Down Expand Up @@ -120,8 +121,12 @@ export class AgentLoader {
console.log(msg);
return;
}
// Detect and report OpenTelemetry globals before attempting to load the agent
this._detectOpenTelemetryGlobals();
// Schedule detection of OpenTelemetry globals after a delay to allow customer application to initialize
const otelDetectionTimeout = setTimeout(() => {
this._detectOpenTelemetryGlobals();
}, OTEL_DETECTION_DELAY_MS);
// Ensure the timeout doesn't prevent the process from exiting
otelDetectionTimeout.unref();
if (this._validate()) {
try {
// Set environment variable to auto attach so the distro is aware of the attach state
Expand Down
37 changes: 37 additions & 0 deletions test/unitTests/agent/agentLoader.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import { LoggerProvider } from "@opentelemetry/sdk-logs";
describe("agent/agentLoader", () => {
let originalEnv: NodeJS.ProcessEnv;
let sandbox: sinon.SinonSandbox;
let clock: sinon.SinonFakeTimers;
let originalOtelGlobalV1: any;
let originalOtelGlobalV2: any;
let originalLogsGlobal: any;
const OTEL_DETECTION_DELAY_MS = 60000; // 1 minute - matches the constant in agentLoader.ts

const defaultConfig = {
azureMonitorExporterOptions: {
Expand Down Expand Up @@ -59,6 +61,7 @@ describe("agent/agentLoader", () => {

beforeEach(() => {
originalEnv = process.env;
clock = sandbox.useFakeTimers();
const otelSymbolV1 = Symbol.for('opentelemetry.js.api.1');
const otelSymbolV2 = Symbol.for('opentelemetry.js.api.2');
const logsSymbol = Symbol.for('io.opentelemetry.js.api.logs');
Expand All @@ -69,6 +72,7 @@ describe("agent/agentLoader", () => {

afterEach(() => {
process.env = originalEnv;
clock.restore();
sandbox.restore();
const otelSymbolV1 = Symbol.for('opentelemetry.js.api.1');
const otelSymbolV2 = Symbol.for('opentelemetry.js.api.2');
Expand Down Expand Up @@ -231,6 +235,39 @@ describe("agent/agentLoader", () => {
assert.ok((logged.message as string).includes("MeterProvider"));
});

it("should delay OpenTelemetry detection by 1 minute after initialize", () => {
const env = {
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
};
process.env = env;
const tracerProvider = new BasicTracerProvider();
trace.setGlobalTracerProvider(tracerProvider);

const agent = new AgentLoader();
const detectGlobalsSpy = sandbox.spy(agent as any, "_detectOpenTelemetryGlobals");
const diagnosticLoggerStub = sandbox.stub(agent["_diagnosticLogger"], "logMessage");
sandbox.stub(agent["_statusLogger"], "logStatus");

agent.initialize();

// Detection should not have been called yet
assert.strictEqual(detectGlobalsSpy.callCount, 0);
// Only the initialization success message should be logged
assert.ok(diagnosticLoggerStub.calledOnce);
assert.strictEqual(diagnosticLoggerStub.args[0][0].messageId, DiagnosticMessageId.attachSuccessful);

// Advance time by less than the delay
clock.tick(OTEL_DETECTION_DELAY_MS - 1);
assert.strictEqual(detectGlobalsSpy.callCount, 0);

// Advance time to trigger the detection
clock.tick(1);
assert.strictEqual(detectGlobalsSpy.callCount, 1);
// Now the conflict message should be logged
assert.strictEqual(diagnosticLoggerStub.callCount, 2);
assert.strictEqual(diagnosticLoggerStub.args[1][0].messageId, DiagnosticMessageId.openTelemetryConflict);
});

it("should log detected OpenTelemetry logger provider via logs symbol getter", () => {
const env = {
["APPLICATIONINSIGHTS_CONNECTION_STRING"]: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333",
Expand Down
Loading