Skip to main content
skill

azure-monitor-opentelemetry-ts — Claude Code skill: setup

This skill guides you through adding Azure Monitor and OpenTelemetry to Node.js apps for Application Insights traces, metrics, and logs.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add microsoft/skills --skill azure-monitor-opentelemetry-ts -a claude-code
Open on GitHub

What azure-monitor-opentelemetry-ts does

The skill covers automatic Node.js instrumentation with @azure/monitor-opentelemetry and manual OpenTelemetry setup. Its examples show custom spans and metrics, plus separate exporters for traces, metrics, and logs. You can also configure which libraries receive instrumentation.

For ESM applications, it gives a loader-based start command for Node.js 18.19+. Call useAzureMonitor() before importing other modules; reversing that order can prevent automatic instrumentation from working. The examples use APPLICATIONINSIGHTS_CONNECTION_STRING to configure the exporter.

The guide also includes custom log ingestion with @azure/monitor-ingestion. When using DefaultAzureCredential in production, set AZURE_TOKEN_CREDENTIALS=prod. Install the skill in Claude Code with the command below; the resulting skill file is at ~/.claude/skills/azure-monitor-opentelemetry-ts/SKILL.md.

What it helps with

  • send Node.js traces, metrics, and logs to Azure Monitor
  • configure automatic instrumentation for HTTP and database libraries
  • create custom OpenTelemetry spans and metrics
  • upload application logs with @azure/monitor-ingestion
  • set up trace, metric, and log exporters manually

Example prompts for the agent

  • Set up automatic Azure Monitor instrumentation for this Node.js app, including traces, metrics, and logs.
  • Add a custom span around order processing and record an exception if it fails.
  • Show me how to export metrics and logs to Azure Monitor manually.

How to install azure-monitor-opentelemetry-ts

1Skills CLI (Vercel)

npx skills add microsoft/skills --skill azure-monitor-opentelemetry-ts -a claude-code

2Manually: put the files in place

~/.claude/skills/azure-monitor-opentelemetry-ts/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/azure-monitor-opentelemetry-ts/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about azure-monitor-opentelemetry-ts

How do I install azure-monitor-opentelemetry-ts in Claude Code?

Run npx skills add microsoft/skills --skill azure-monitor-opentelemetry-ts -a claude-code. The skill file is located at ~/.claude/skills/azure-monitor-opentelemetry-ts/SKILL.md.

What does azure-monitor-opentelemetry-ts do?

It guides setup of Azure Monitor and OpenTelemetry for Node.js applications. The examples cover automatic instrumentation, custom telemetry, and sending data to Application Insights.

What configuration does the skill use for Application Insights?

The exporter examples read APPLICATIONINSIGHTS_CONNECTION_STRING. For production use of DefaultAzureCredential, set AZURE_TOKEN_CREDENTIALS=prod.

Source text

SKILL.md · MIT
---
name: azure-monitor-opentelemetry-ts
description: 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.
license: MIT
metadata:
  author: Microsoft
  version: "1.0.0"
  package: '@azure/monitor-opentelemetry'
---

# Azure Monitor OpenTelemetry SDK for TypeScript

Auto-instrument Node.js applications with distributed tracing, metrics, and logs.

## Installation

```bash
# Distro (recommended - auto-instrumentation)
npm install @azure/monitor-opentelemetry

# Low-level exporters (custom OpenTelemetry setup)
npm install @azure/monitor-opentelemetry-exporter

# Custom logs ingestion
npm install @azure/monitor-ingestion
```

## Environment Variables

```bash
APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=...;IngestionEndpoint=...
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production
```

## Quick Start (Auto-Instrumentation)

**IMPORTANT:** Call `useAzureMonitor()` BEFORE importing other modules.

```typescript
import { useAzureMonitor } from "@azure/monitor-opentelemetry";

useAzureMonitor({
  azureMonitorExporterOptions: {
    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
  }
});

// Now import your application
import express from "express";
const app = express();
```

## ESM Support (Node.js 18.19+)

```bash
node --import @azure/monitor-opentelemetry/loader ./dist/index.js
```

**package.json:**
```json
{
  "scripts": {
    "start": "node --import @azure/monitor-opentelemetry/loader ./dist/index.js"
  }
}
```

## Full Configuration

```typescript
import { useAzureMonitor, AzureMonitorOpenTelemetryOptions } from "@azure/monitor-opentelemetry";
import { resourceFromAttributes } from "@opentelemetry/resources";

const options: AzureMonitorOpenTelemetryOptions = {
  azureMonitorExporterOptions: {
    connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
    storageDirectory: "/path/to/offline/storage",
    disableOfflineStorage: false
  },
  
  // Sampling
  samplingRatio: 1.0,  // 0-1, percentage of traces
  
  // Features
  enableLiveMetrics: true,
  enableStandardMetrics: true,
  enablePerformanceCounters: true,
  
  // Instrumentation libraries
  instrumentationOptions: {
    azureSdk: { enabled: true },
    http: { enabled: true },
    mongoDb: { enabled: true },
    mySql: { enabled: true },
    postgreSql: { enabled: true },
    redis: { enabled: true },
    bunyan: { enabled: false },
    winston: { enabled: false }
  },
  
  // Custom resource
  resource: resourceFromAttributes({ "service.name": "my-service" })
};

useAzureMonitor(options);
```

## Custom Traces

```typescript
import { trace } from "@opentelemetry/api";

const tracer = trace.getTracer("my-tracer");

const span = tracer.startSpan("doWork");
try {
  span.setAttribute("component", "worker");
  span.setAttribute("operation.id", "42");
  span.addEvent("processing started");
  
  // Your work here
  
} catch (error) {
  span.recordException(error as Error);
  span.setStatus({ code: 2, message: (error as Error).message });
} finally {
  span.end();
}
```

## Custom Metrics

```typescript
import { metrics } from "@opentelemetry/api";

const meter = metrics.getMeter("my-meter");

// Counter
const counter = meter.createCounter("requests_total");
counter.add(1, { route: "/api/users", method: "GET" });

// Histogram
const histogram = meter.createHistogram("request_duration_ms");
histogram.record(150, { route: "/api/users" });

// Observable Gauge
const gauge = meter.createObservableGauge("active_connections");
gauge.addCallback((result) => {
  result.observe(getActiveConnections(), { pool: "main" });
});
```

## Manual Exporter Setup

### Trace Exporter

```typescript
import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";
import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";

const exporter = new AzureMonitorTraceExporter({
  connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
});

const provider = new NodeTracerProvider({
  spanProcessors: [new BatchSpanProcessor(exporter)]
});

provider.register();
```

### Metric Exporter

```typescript
import { AzureMonitorMetricExporter } from "@azure/monitor-opentelemetry-exporter";
import { PeriodicExportingMetricReader, MeterProvider } from "@opentelemetry/sdk-metrics";
import { metrics } from "@opentelemetry/api";

const exporter = new AzureMonitorMetricExporter({
  connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
});

const meterProvider = new MeterProvider({
  readers: [new PeriodicExportingMetricReader({ exporter })]
});

metrics.setGlobalMeterProvider(meterProvider);
```

### Log Exporter

```typescript
import { AzureMonitorLogExporter } from "@azure/monitor-opentelemetry-exporter";
import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
import { logs } from "@opentelemetry/api-logs";

const exporter = new AzureMonitorLogExporter({
  connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING
});

const loggerProvider = new LoggerProvider();
loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(exporter));

logs.setGlobalLoggerProvider(loggerProvider);
```

## Custom Logs Ingestion

```typescript
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
import { LogsIngestionClient, isAggregateLogsUploadError } from "@azure/monitor-ingestion";

const endpoint = "https://<dce>.ingest.monitor.azure.com";
const ruleId = "<data-collection-rule-id>";
const streamName = "Custom-MyTable_CL";

// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();

const client = new LogsIngestionClient(endpoint, credential);

const logs = [
  {
    Time: new Date().toISOString(),
    Computer: "Server1",
    Message: "Application started",
    Level: "Information"
  }
];

try {
  await client.upload(ruleId, streamName, logs);
} catch (error) {
  if (isAggregateLogsUploadError(error)) {
    for (const uploadError of error.errors) {
      console.error("Failed logs:", uploadError.failedLogs);
    }
  }
}
```

## Custom Span Processor

```typescript
import { SpanProcessor, ReadableSpan } from "@opentelemetry/sdk-trace-base";
import { Span, Context, SpanKind, TraceFlags } from "@opentelemetry/api";
import { useAzureMonitor } from "@azure/monitor-opentelemetry";

class FilteringSpanProcessor implements SpanProcessor {
  forceFlush(): Promise<void> { return Promise.resolve(); }
  shutdown(): Promise<void> { return Promise.resolve(); }
  onStart(span: Span, context: Context): void {}
  
  onEnd(span: ReadableSpan): void {
    // Add custom attributes
    span.attributes["CustomDimension"] = "value";
    
    // Filter out internal spans
    if (span.kind === SpanKind.INTERNAL) {
      span.spanContext().traceFlags = TraceFlags.NONE;
    }
  }
}

useAzureMonitor({
  spanProcessors: [new FilteringSpanProcessor()]
});
```

## Sampling

```typescript
import { ApplicationInsightsSampler } from "@azure/monitor-opentelemetry-exporter";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";

// Sample 75% of traces
const sampler = new ApplicationInsightsSampler(0.75);

const provider = new NodeTracerProvider({ sampler });
```

## Shutdown

```typescript
import { useAzureMonitor, shutdownAzureMonitor } from "@azure/monitor-opentelemetry";

useAzureMonitor();

// On application shutdown
process.on("SIGTERM", async () => {
  await shutdownAzureMonitor();
  process.exit(0);
});
```

## Key Types

```typescript
import {
  useAzureMonitor,
  shutdownAzureMonitor,
  AzureMonitorOpenTelemetryOptions,
  InstrumentationOptions
} from "@azure/monitor-opentelemetry";

import {
  AzureMonitorTraceExporter,
  AzureMonitorMetricExporter,
  AzureMonitorLogExporter,
  ApplicationInsightsSampler,
  AzureMonitorExporterOptions
} from "@azure/monitor-opentelemetry-exporter";

import {
  LogsIngestionClient,
  isAggregateLogsUploadError
} from "@azure/monitor-ingestion";
```

## Best Practices

1. **Call useAzureMonitor() first** - Before importing other modules
2. **Use ESM loader for ESM projects** - `--import @azure/monitor-opentelemetry/loader`
3. **Enable offline storage** - For reliable telemetry in disconnected scenarios
4. **Set sampling ratio** - For high-traffic applications
5. **Add custom dimensions** - Use span processors for enrichment
6. **Graceful shutdown** - Call `shutdownAzureMonitor()` to flush telemetry

© Microsoft · MIT · microsoft/skills

Similar skills

All skills for Cloud: AWS, Azure, GCP →

From the same set143

The whole set →
m365-agents-ts Build TypeScript agents for Microsoft 365, Teams, and Copilot Studio with examples for routing, Express hosting, streaming replies, and Copilot Studio integration. 1installs azure-storage-queue-ts This skill guides TypeScript and JavaScript work with Azure Queue Storage, from sending messages to processing and deleting them. Use it when building queue-backed tasks. 1installs azure-storage-file-share-ts A skill that feeds the agent working TypeScript examples for Azure File Share via the @azure/storage-file-share SDK: shares, directories, uploads and downloads. 1installs azure-search-documents-ts A skill that gives your agent working TypeScript patterns for the Azure AI Search SDK: indexes, vector and hybrid search, semantic ranking. 1installs azure-keyvault-keys-ts This skill guides TypeScript work with Azure Key Vault keys, from creation and rotation to encryption and signing. Use it when building with the @azure/keyvault-keys SDK. 1installs azure-identity-ts A skill that walks the agent through Azure authentication with the @azure/identity library in TypeScript. Useful once DefaultAzureCredential or managed identity shows up in your code. 1installs azure-cosmos-ts A skill covering the Azure Cosmos DB JavaScript/TypeScript SDK: document CRUD, queries, bulk operations. Useful when the agent writes data-access code. 1installs azure-appconfiguration-ts A skill that gets your agent writing TypeScript against Azure App Configuration: settings, feature flags, Key Vault references and dynamic refresh. 1installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor