diff --git a/sdk/monitor/monitor-opentelemetry/CHANGELOG.md b/sdk/monitor/monitor-opentelemetry/CHANGELOG.md
index a55cc88912ce..78c75bb38934 100644
--- a/sdk/monitor/monitor-opentelemetry/CHANGELOG.md
+++ b/sdk/monitor/monitor-opentelemetry/CHANGELOG.md
@@ -1,5 +1,11 @@
# Release History
+### 1.15.0 ()
+
+### Features Added
+
+- Allow configuring additional metric views through `AzureMonitorOpenTelemetryOptions` and pass them to the NodeSDK.
+
### 1.14.2 (2025-11-13)
### Bugs Fixed
diff --git a/sdk/monitor/monitor-opentelemetry/README.md b/sdk/monitor/monitor-opentelemetry/README.md
index 9ebde71f3c27..0691e2515f8a 100644
--- a/sdk/monitor/monitor-opentelemetry/README.md
+++ b/sdk/monitor/monitor-opentelemetry/README.md
@@ -81,6 +81,7 @@ const options: AzureMonitorOpenTelemetryOptions = {
resource: resource,
logRecordProcessors: [],
spanProcessors: [],
+ views: [],
};
useAzureMonitor(options);
```
@@ -159,6 +160,11 @@ useAzureMonitor(options);
Array of span processors to register to the global tracer provider. |
|
+
+ views |
+ Array of metric views to register to the global meter provider. |
+ |
+
enableTraceBasedSamplingForLogs |
Enable log sampling based on trace. |
diff --git a/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md b/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md
index 6552dc12512d..2fa9d64d9116 100644
--- a/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md
+++ b/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md
@@ -11,6 +11,7 @@ import type { MetricReader } from '@opentelemetry/sdk-metrics';
import { NodeSDK } from '@opentelemetry/sdk-node';
import type { Resource } from '@opentelemetry/resources';
import type { SpanProcessor } from '@opentelemetry/sdk-trace-base';
+import type { ViewOptions } from '@opentelemetry/sdk-metrics';
// @public
export interface AzureMonitorOpenTelemetryOptions {
@@ -27,6 +28,7 @@ export interface AzureMonitorOpenTelemetryOptions {
samplingRatio?: number;
spanProcessors?: SpanProcessor[];
tracesPerSecond?: number;
+ views?: ViewOptions[];
}
// @public
diff --git a/sdk/monitor/monitor-opentelemetry/src/index.ts b/sdk/monitor/monitor-opentelemetry/src/index.ts
index 12bea406987d..1ccdfefe38cf 100644
--- a/sdk/monitor/monitor-opentelemetry/src/index.ts
+++ b/sdk/monitor/monitor-opentelemetry/src/index.ts
@@ -5,7 +5,7 @@ import { metrics, trace } from "@opentelemetry/api";
import { logs } from "@opentelemetry/api-logs";
import type { NodeSDKConfiguration } from "@opentelemetry/sdk-node";
import { NodeSDK } from "@opentelemetry/sdk-node";
-import type { MetricReader } from "@opentelemetry/sdk-metrics";
+import type { MetricReader, ViewOptions } from "@opentelemetry/sdk-metrics";
import { InternalConfig } from "./shared/config.js";
import { MetricHandler } from "./metrics/index.js";
import { TraceHandler } from "./traces/handler.js";
@@ -81,6 +81,7 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions): voi
// Add extra SpanProcessors, and logRecordProcessors from user configuration
const spanProcessors: SpanProcessor[] = options?.spanProcessors || [];
const logRecordProcessors: LogRecordProcessor[] = options?.logRecordProcessors || [];
+ const customViews: ViewOptions[] = options?.views || [];
// Prepare metric readers - always include Azure Monitor
const metricReaders: MetricReader[] = [
@@ -88,11 +89,13 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions): voi
...(options?.metricReaders || []),
];
+ const views: ViewOptions[] = metricHandler.getViews().concat(customViews);
+
// Initialize OpenTelemetry SDK
const sdkConfig: Partial = {
autoDetectResources: true,
metricReaders: metricReaders,
- views: metricHandler.getViews(),
+ views,
instrumentations: instrumentations,
logRecordProcessors: [
logHandler.getAzureLogRecordProcessor(),
diff --git a/sdk/monitor/monitor-opentelemetry/src/types.ts b/sdk/monitor/monitor-opentelemetry/src/types.ts
index 6370c27d962f..8a95d35a4a3e 100644
--- a/sdk/monitor/monitor-opentelemetry/src/types.ts
+++ b/sdk/monitor/monitor-opentelemetry/src/types.ts
@@ -4,7 +4,7 @@ import type { AzureMonitorExporterOptions } from "@azure/monitor-opentelemetry-e
import type { InstrumentationConfig } from "@opentelemetry/instrumentation";
import type { Resource } from "@opentelemetry/resources";
import type { LogRecordProcessor } from "@opentelemetry/sdk-logs";
-import type { MetricReader } from "@opentelemetry/sdk-metrics";
+import type { MetricReader, ViewOptions } from "@opentelemetry/sdk-metrics";
import type { SpanProcessor } from "@opentelemetry/sdk-trace-base";
/**
@@ -37,6 +37,8 @@ export interface AzureMonitorOpenTelemetryOptions {
spanProcessors?: SpanProcessor[];
/** An array of metric readers to register to the meter provider.*/
metricReaders?: MetricReader[];
+ /** An array of metric views to register to the meter provider.*/
+ views?: ViewOptions[];
}
/**
diff --git a/sdk/monitor/monitor-opentelemetry/test/internal/unit/main.test.ts b/sdk/monitor/monitor-opentelemetry/test/internal/unit/main.test.ts
index b19fb907a8c6..222da1b00c48 100644
--- a/sdk/monitor/monitor-opentelemetry/test/internal/unit/main.test.ts
+++ b/sdk/monitor/monitor-opentelemetry/test/internal/unit/main.test.ts
@@ -6,7 +6,7 @@ import { metrics, trace } from "@opentelemetry/api";
import { logs } from "@opentelemetry/api-logs";
import type { AzureMonitorOpenTelemetryOptions } from "../../../src/index.js";
import { useAzureMonitor, shutdownAzureMonitor, _getSdkInstance } from "../../../src/index.js";
-import type { MeterProvider } from "@opentelemetry/sdk-metrics";
+import type { MeterProvider, ViewOptions } from "@opentelemetry/sdk-metrics";
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import type { StatsbeatEnvironmentConfig } from "../../../src/types.js";
@@ -155,6 +155,21 @@ describe("Main functions", () => {
expect(spyonEmit).toHaveBeenCalled();
});
+ it("should add custom metric views", () => {
+ const customView: ViewOptions = { meterName: "custom-meter" };
+ const config: AzureMonitorOpenTelemetryOptions = {
+ azureMonitorExporterOptions: {
+ connectionString: "InstrumentationKey=00000000-0000-0000-0000-000000000000",
+ },
+ views: [customView],
+ };
+ useAzureMonitor(config);
+ // eslint-disable-next-line no-underscore-dangle
+ const meterConfig = (_getSdkInstance() as any)?._meterProviderConfig;
+ expect(meterConfig).toBeDefined();
+ expect(meterConfig?.views).toContain(customView);
+ });
+
it("should set statsbeat features", () => {
const config: AzureMonitorOpenTelemetryOptions = {
azureMonitorExporterOptions: {
diff --git a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts
index 74c58d200d92..c05317150624 100644
--- a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts
+++ b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts
@@ -17,6 +17,7 @@ import { expect, afterEach, assert, beforeAll, describe, it, afterAll, vi } from
import type Http from "node:http";
import { ExportResultCode } from "@opentelemetry/core";
import type { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";
+import type { Instrumentation } from "@opentelemetry/instrumentation";
describe("Library/TraceHandler", () => {
let http: typeof Http | null = null;
@@ -28,6 +29,7 @@ describe("Library/TraceHandler", () => {
const mockHttpServerPort = 8085;
let tracerProvider: NodeTracerProvider;
let exportSpy: MockInstance;
+ let activeInstrumentations: Instrumentation[] = [];
beforeAll(async () => {
_config = new InternalConfig();
@@ -71,6 +73,8 @@ describe("Library/TraceHandler", () => {
});
afterEach(async () => {
+ activeInstrumentations.forEach((instrumentation) => instrumentation.disable());
+ activeInstrumentations = [];
await metricHandler.shutdown();
await handler.shutdown();
metrics.disable();
@@ -82,6 +86,10 @@ describe("Library/TraceHandler", () => {
_config.instrumentationOptions.http = httpConfig;
metricHandler = new MetricHandler(_config);
handler = new TraceHandler(_config, metricHandler);
+ handler.getInstrumentations().forEach((instrumentation) => {
+ instrumentation.enable();
+ activeInstrumentations.push(instrumentation);
+ });
// Because the instrumentation is registered globally, its config is not updated
// when the handler is created. We need to mock the getConfig method to return
@@ -158,6 +166,9 @@ describe("Library/TraceHandler", () => {
],
});
trace.setGlobalTracerProvider(tracerProvider);
+ activeInstrumentations.forEach((instrumentation) => {
+ instrumentation.setTracerProvider(tracerProvider);
+ });
await makeHttpRequest();
await tracerProvider.forceFlush();
expect(exportSpy).toHaveBeenCalledOnce();
diff --git a/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts b/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts
index f6faf0bf3557..c9d6fe379d88 100644
--- a/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts
+++ b/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts
@@ -67,6 +67,7 @@ describe("snippets", () => {
resource: resource,
logRecordProcessors: [],
spanProcessors: [],
+ views: [],
};
useAzureMonitor(options);