MicrosoftAgentsSKILL.mdVerified source

Agent Skill

Azure Monitor OpenTelemetry for TypeScript

Add distributed traces, metrics, and logs to Node.js services with Azure Monitor and OpenTelemetry.

azure-monitoropentelemetryobservability

Skill specification

Declared by Microsoft in the package front matter. Trigger conditions are what the coding agent matches on before it loads the skill.

Azure Monitor OpenTelemetry for TypeScript SKILL.md front matter fields
Skill nameazure-monitor-opentelemetry-ts
Trigger conditionsInstrument 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.
Declared licenseMIT
Version1.0.0
AuthorMicrosoft
Package@azure/monitor-opentelemetry

Install azure-monitor-opentelemetry-ts

Agent Skills are a shared file format, but each client discovers them from a different directory. Copy the command for your agent, then start a new session so the skill is picked up.

Claude Code

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

Project skills are committed with the repo. Use the user directory for a personal install across every project.

Project install

mkdir -p .claude/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o .claude/skills/azure-monitor-opentelemetry-ts/SKILL.md

Personal install

mkdir -p ~/.claude/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o ~/.claude/skills/azure-monitor-opentelemetry-ts/SKILL.md

Codex

.agents/skills/azure-monitor-opentelemetry-ts/SKILL.md

Codex reads `.agents/skills/` as its primary location, which is also the cross-platform default other clients honour.

Project install

mkdir -p .agents/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o .agents/skills/azure-monitor-opentelemetry-ts/SKILL.md

Personal install

mkdir -p ~/.agents/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o ~/.agents/skills/azure-monitor-opentelemetry-ts/SKILL.md

Cursor

.cursor/skills/azure-monitor-opentelemetry-ts/SKILL.md

Cursor also loads `.agents/skills/`, `.claude/skills/`, and `.codex/skills/`, so one committed copy can serve several clients.

Project install

mkdir -p .cursor/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o .cursor/skills/azure-monitor-opentelemetry-ts/SKILL.md

Personal install

mkdir -p ~/.cursor/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o ~/.cursor/skills/azure-monitor-opentelemetry-ts/SKILL.md

Gemini CLI

.gemini/skills/azure-monitor-opentelemetry-ts/SKILL.md

Gemini CLI reads `.agents/skills/` first when both directories exist.

Project install

mkdir -p .gemini/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o .gemini/skills/azure-monitor-opentelemetry-ts/SKILL.md

Personal install

mkdir -p ~/.gemini/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o ~/.gemini/skills/azure-monitor-opentelemetry-ts/SKILL.md

GitHub Copilot

.github/skills/azure-monitor-opentelemetry-ts/SKILL.md

Copilot in VS Code discovers repository skills from `.github/skills/`.

Project install

mkdir -p .github/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o .github/skills/azure-monitor-opentelemetry-ts/SKILL.md

Personal install

mkdir -p ~/.copilot/skills/azure-monitor-opentelemetry-ts && curl -fsSL 'https://raw.githubusercontent.com/microsoft/skills/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts/SKILL.md' -o ~/.copilot/skills/azure-monitor-opentelemetry-ts/SKILL.md

Published by Microsoft under MIT. Rendered from the package in github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-typescript/skills/azure-monitor-opentelemetry-ts.

Azure Monitor OpenTelemetry SDK for TypeScript

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

Installation

# 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

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.

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+)

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

package.json:

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

Full Configuration

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

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

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

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

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

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

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

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

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

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

useAzureMonitor();

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

Key Types

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

Add the registry badge

Maintainers can link this listing from the skill's own README. Free, no account needed, and it points back at the rendered package for anyone browsing the repo.

Markdown

[![Azure Monitor OpenTelemetry for TypeScript on tokens&](https://tokensand.com/api/badges/skill/microsoft-azure-monitor-opentelemetry-ts)](https://tokensand.com/agent-skills/microsoft-azure-monitor-opentelemetry-ts)

HTML

<a href="https://tokensand.com/agent-skills/microsoft-azure-monitor-opentelemetry-ts" target="_blank" rel="noopener">
  <img src="https://tokensand.com/api/badges/skill/microsoft-azure-monitor-opentelemetry-ts" alt="Azure Monitor OpenTelemetry for TypeScript on tokens&" />
</a>

More Microsoft Agent Skills

All Agent Skills