Instrument applications with Azure Monitor and OpenTelemetry for JavaScript (@azure/monitor-opentelemetry). Use when adding distributed tracing, metrics, and logs to Node.js applications with Application Insights.
Add this skill
npx mdskills install sickn33/azure-monitor-opentelemetry-tsComprehensive reference guide for Azure Monitor OpenTelemetry integration with clear examples
1---2name: azure-monitor-opentelemetry-ts3description: Instrument applications with Azure Monitor and OpenTelemetry for JavaScript (@azure/monitor-opentelemetry). Use when adding distributed tracing, metrics, and logs to Node.js applications with Application Insights.4package: "@azure/monitor-opentelemetry"5---67# Azure Monitor OpenTelemetry SDK for TypeScript89Auto-instrument Node.js applications with distributed tracing, metrics, and logs.1011## Installation1213```bash14# Distro (recommended - auto-instrumentation)15npm install @azure/monitor-opentelemetry1617# Low-level exporters (custom OpenTelemetry setup)18npm install @azure/monitor-opentelemetry-exporter1920# Custom logs ingestion21npm install @azure/monitor-ingestion22```2324## Environment Variables2526```bash27APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=...;IngestionEndpoint=...28```2930## Quick Start (Auto-Instrumentation)3132**IMPORTANT:** Call `useAzureMonitor()` BEFORE importing other modules.3334```typescript35import { useAzureMonitor } from "@azure/monitor-opentelemetry";3637useAzureMonitor({38 azureMonitorExporterOptions: {39 connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING40 }41});4243// Now import your application44import express from "express";45const app = express();46```4748## ESM Support (Node.js 18.19+)4950```bash51node --import @azure/monitor-opentelemetry/loader ./dist/index.js52```5354**package.json:**55```json56{57 "scripts": {58 "start": "node --import @azure/monitor-opentelemetry/loader ./dist/index.js"59 }60}61```6263## Full Configuration6465```typescript66import { useAzureMonitor, AzureMonitorOpenTelemetryOptions } from "@azure/monitor-opentelemetry";67import { resourceFromAttributes } from "@opentelemetry/resources";6869const options: AzureMonitorOpenTelemetryOptions = {70 azureMonitorExporterOptions: {71 connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,72 storageDirectory: "/path/to/offline/storage",73 disableOfflineStorage: false74 },7576 // Sampling77 samplingRatio: 1.0, // 0-1, percentage of traces7879 // Features80 enableLiveMetrics: true,81 enableStandardMetrics: true,82 enablePerformanceCounters: true,8384 // Instrumentation libraries85 instrumentationOptions: {86 azureSdk: { enabled: true },87 http: { enabled: true },88 mongoDb: { enabled: true },89 mySql: { enabled: true },90 postgreSql: { enabled: true },91 redis: { enabled: true },92 bunyan: { enabled: false },93 winston: { enabled: false }94 },9596 // Custom resource97 resource: resourceFromAttributes({ "service.name": "my-service" })98};99100useAzureMonitor(options);101```102103## Custom Traces104105```typescript106import { trace } from "@opentelemetry/api";107108const tracer = trace.getTracer("my-tracer");109110const span = tracer.startSpan("doWork");111try {112 span.setAttribute("component", "worker");113 span.setAttribute("operation.id", "42");114 span.addEvent("processing started");115116 // Your work here117118} catch (error) {119 span.recordException(error as Error);120 span.setStatus({ code: 2, message: (error as Error).message });121} finally {122 span.end();123}124```125126## Custom Metrics127128```typescript129import { metrics } from "@opentelemetry/api";130131const meter = metrics.getMeter("my-meter");132133// Counter134const counter = meter.createCounter("requests_total");135counter.add(1, { route: "/api/users", method: "GET" });136137// Histogram138const histogram = meter.createHistogram("request_duration_ms");139histogram.record(150, { route: "/api/users" });140141// Observable Gauge142const gauge = meter.createObservableGauge("active_connections");143gauge.addCallback((result) => {144 result.observe(getActiveConnections(), { pool: "main" });145});146```147148## Manual Exporter Setup149150### Trace Exporter151152```typescript153import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";154import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";155156const exporter = new AzureMonitorTraceExporter({157 connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING158});159160const provider = new NodeTracerProvider({161 spanProcessors: [new BatchSpanProcessor(exporter)]162});163164provider.register();165```166167### Metric Exporter168169```typescript170import { AzureMonitorMetricExporter } from "@azure/monitor-opentelemetry-exporter";171import { PeriodicExportingMetricReader, MeterProvider } from "@opentelemetry/sdk-metrics";172import { metrics } from "@opentelemetry/api";173174const exporter = new AzureMonitorMetricExporter({175 connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING176});177178const meterProvider = new MeterProvider({179 readers: [new PeriodicExportingMetricReader({ exporter })]180});181182metrics.setGlobalMeterProvider(meterProvider);183```184185### Log Exporter186187```typescript188import { AzureMonitorLogExporter } from "@azure/monitor-opentelemetry-exporter";189import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";190import { logs } from "@opentelemetry/api-logs";191192const exporter = new AzureMonitorLogExporter({193 connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING194});195196const loggerProvider = new LoggerProvider();197loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(exporter));198199logs.setGlobalLoggerProvider(loggerProvider);200```201202## Custom Logs Ingestion203204```typescript205import { DefaultAzureCredential } from "@azure/identity";206import { LogsIngestionClient, isAggregateLogsUploadError } from "@azure/monitor-ingestion";207208const endpoint = "https://<dce>.ingest.monitor.azure.com";209const ruleId = "<data-collection-rule-id>";210const streamName = "Custom-MyTable_CL";211212const client = new LogsIngestionClient(endpoint, new DefaultAzureCredential());213214const logs = [215 {216 Time: new Date().toISOString(),217 Computer: "Server1",218 Message: "Application started",219 Level: "Information"220 }221];222223try {224 await client.upload(ruleId, streamName, logs);225} catch (error) {226 if (isAggregateLogsUploadError(error)) {227 for (const uploadError of error.errors) {228 console.error("Failed logs:", uploadError.failedLogs);229 }230 }231}232```233234## Custom Span Processor235236```typescript237import { SpanProcessor, ReadableSpan } from "@opentelemetry/sdk-trace-base";238import { Span, Context, SpanKind, TraceFlags } from "@opentelemetry/api";239import { useAzureMonitor } from "@azure/monitor-opentelemetry";240241class FilteringSpanProcessor implements SpanProcessor {242 forceFlush(): Promise<void> { return Promise.resolve(); }243 shutdown(): Promise<void> { return Promise.resolve(); }244 onStart(span: Span, context: Context): void {}245246 onEnd(span: ReadableSpan): void {247 // Add custom attributes248 span.attributes["CustomDimension"] = "value";249250 // Filter out internal spans251 if (span.kind === SpanKind.INTERNAL) {252 span.spanContext().traceFlags = TraceFlags.NONE;253 }254 }255}256257useAzureMonitor({258 spanProcessors: [new FilteringSpanProcessor()]259});260```261262## Sampling263264```typescript265import { ApplicationInsightsSampler } from "@azure/monitor-opentelemetry-exporter";266import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";267268// Sample 75% of traces269const sampler = new ApplicationInsightsSampler(0.75);270271const provider = new NodeTracerProvider({ sampler });272```273274## Shutdown275276```typescript277import { useAzureMonitor, shutdownAzureMonitor } from "@azure/monitor-opentelemetry";278279useAzureMonitor();280281// On application shutdown282process.on("SIGTERM", async () => {283 await shutdownAzureMonitor();284 process.exit(0);285});286```287288## Key Types289290```typescript291import {292 useAzureMonitor,293 shutdownAzureMonitor,294 AzureMonitorOpenTelemetryOptions,295 InstrumentationOptions296} from "@azure/monitor-opentelemetry";297298import {299 AzureMonitorTraceExporter,300 AzureMonitorMetricExporter,301 AzureMonitorLogExporter,302 ApplicationInsightsSampler,303 AzureMonitorExporterOptions304} from "@azure/monitor-opentelemetry-exporter";305306import {307 LogsIngestionClient,308 isAggregateLogsUploadError309} from "@azure/monitor-ingestion";310```311312## Best Practices3133141. **Call useAzureMonitor() first** - Before importing other modules3152. **Use ESM loader for ESM projects** - `--import @azure/monitor-opentelemetry/loader`3163. **Enable offline storage** - For reliable telemetry in disconnected scenarios3174. **Set sampling ratio** - For high-traffic applications3185. **Add custom dimensions** - Use span processors for enrichment3196. **Graceful shutdown** - Call `shutdownAzureMonitor()` to flush telemetry320
Full transparency — inspect the skill content before installing.