ApplicationInsights-JS

OpenTelemetry Tracing API in Application Insights JavaScript SDK

Overview

The Application Insights JavaScript SDK provides an OpenTelemetry (OTel) compatible tracing API, allowing you to instrument your applications using familiar OpenTelemetry-like APIs for distributed tracing while automatically sending telemetry to Azure Application Insights. This implementation focuses on tracing support only (not metrics or logs) and bridges the gap between OpenTelemetry’s vendor-neutral instrumentation patterns and Application Insights’ powerful monitoring capabilities.

Note: This is an OpenTelemetry-compatible tracing API implementation, not a full OpenTelemetry SDK. It provides a Tracing API interface following OpenTelemetry conventions but does not include all span operations, metrics or logging APIs.

What is OpenTelemetry?

OpenTelemetry is an open-source observability framework for cloud-native software. It provides a single set of APIs, libraries, and conventions for capturing distributed traces, metrics, and logs from your applications.

Application Insights Implementation: The Application Insights JavaScript SDK implements an OpenTelemetry like compatible tracing API. This means you can use familiar OpenTelemetry tracing patterns for distributed trace instrumentation. However, this is not a full OpenTelemetry SDK implementation - only the tracing API is supported (metrics and logs APIs are not included).

Why Use the OpenTelemetry-compatible Tracing API?

Core Concepts

1. OTel API (IOTelApi)

The main entry point for OpenTelemetry functionality. Provides access to tracers and the trace API.

2. Trace API (ITraceApi)

Manages tracer instances and provides utilities for span context management.

3. Tracer (IOTelTracer)

Creates and manages spans. Each tracer typically represents a specific component or service.

4. Span (IReadableSpan)

Represents a unit of work in a distributed trace. Contains timing, attributes, and context information.

5. Tracer Methods

6. Standalone Helper Functions

7. Application Insights Functions (ITraceHost)

Direct access to OpenTelemetry trace operations available on appInsights or core instances:

These methods provide direct control over span lifecycle and context management as the main appInsights manages an internal Tracer (IOTelTracer).

Quick Start

Installation

The OpenTelemetry-compatible tracing APIs are built into the Application Insights packages:

npm install @microsoft/applicationinsights-web
# or for core only (by default does not initialize any trace provider
# which means core.startSpan() will return null)
npm install @microsoft/applicationinsights-core-js

No additional OpenTelemetry packages are required for tracing. The tracing API is included in the core SDK.

Basic Usage

import { ApplicationInsights } from '@microsoft/applicationinsights-web';

// Initialize Application Insights
const appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING'
    }
});
appInsights.loadAppInsights();

// Get the OpenTelemetry API
const otelApi = appInsights.otelApi;

// Get a tracer for your service
const tracer = otelApi.trace.getTracer('my-service');

// Create a span
const span = tracer.startSpan('user-operation');
span.setAttribute('user.id', '12345');
span.setAttribute('operation.type', 'checkout');

try {
    // Perform your operation
    await processCheckout();
    span.setStatus({ code: SpanStatusCode.OK });
} catch (error) {
    span.setStatus({ 
        code: SpanStatusCode.ERROR,
        message: error.message 
    });
} finally {
    span.end(); // Always end the span
}

The startActiveSpan standalone helper function provides automatic context management:

import { startActiveSpan } from '@microsoft/applicationinsights-core-js';

const result = await startActiveSpan(appInsights, 'process-payment', async (scope) => {
    scope.span.setAttribute('payment.method', 'credit_card');
    
    try {
        const response = await processPayment();
        scope.span.setAttribute('payment.status', 'success');
        return response;
    } catch (error) {
        scope.span.setStatus({ 
            code: SpanStatusCode.ERROR,
            message: error.message 
        });
        throw error;
    }
    // Span is automatically ended when function completes
});

Using startSpan Directly on the SKU

The Application Insights SKU instance (appInsights) is itself a tracer, so you can call startSpan directly without obtaining a tracer first.

Important: startSpan() creates a span but does NOT set it as the active span. This means:

// Direct usage - creates span but does NOT set it as active
const span = appInsights.startSpan('quick-operation', {
    kind: OTelSpanKind.INTERNAL,
    attributes: {
        'user.id': '12345',
        'operation.type': 'data-fetch'
    }
});

if (span) {
    try {
        // Perform operation
        const data = await fetchData();
        span.setAttribute('items.count', data.length);
        span.setStatus({ code: SpanStatusCode.OK });
    } catch (error) {
        span.setStatus({ 
            code: SpanStatusCode.ERROR,
            message: error.message 
        });
    } finally {
        span.end();
    }
}

When to use direct startSpan vs obtaining a tracer:

Both approaches create identical telemetry, but using the direct startSpan method is simpler and recommended for most applications.

Documentation Structure

This folder contains comprehensive documentation on all OpenTelemetry features:

Core API Documentation

Helper Functions

Guides and Examples

Key Features

Automatic Telemetry Creation

When you end a span, Application Insights automatically:

Nested Spans

Create hierarchical traces with parent-child relationships:

tracer.startActiveSpan('parent-operation', (parentSpan) => {
    parentSpan.setAttribute('step', 'starting');
    
    // Child spans automatically inherit parent context
    tracer.startActiveSpan('child-operation', (childSpan) => {
        childSpan.setAttribute('detail', 'processing');
        // Work here
    });
    
    parentSpan.setAttribute('step', 'completed');
});

Distributed Tracing

Propagate trace context across service boundaries:

// Service A: Create a span and extract context
const span = tracer.startSpan('api-call');
const traceContext = span.spanContext();

// Pass traceContext to Service B (e.g., via HTTP headers)
const headers = {
    'traceparent': `00-${traceContext.traceId}-${traceContext.spanId}-01`
};

// Service B: Create child span from propagated context
const childSpan = tracer.startSpan('process-request', {
    parent: traceContext
});

Multiple Services/Components

Use different tracers for different parts of your application:

const userServiceTracer = otelApi.trace.getTracer('user-service');
const paymentTracer = otelApi.trace.getTracer('payment-service');

// Each tracer can be used independently
const userSpan = userServiceTracer.startSpan('authenticate');
const paymentSpan = paymentTracer.startSpan('process-payment');

Browser Compatibility

The OpenTelemetry implementation in Application Insights JavaScript SDK supports:

Performance Considerations

The OpenTelemetry implementation is designed for minimal performance impact:

Migration Guide

From OpenTelemetry SDK

If you’re migrating from @opentelemetry/api:

  1. Replace @opentelemetry/api tracing imports with Application Insights imports
  2. Use appInsights.otelApi or appInsights.trace to access the tracing API
  3. Most tracing API signatures are compatible
  4. Telemetry automatically flows to Application Insights

Important Limitations:

Multiple Ways to Create Spans

Application Insights provides several methods to create spans:

Using Direct startSpan (Recommended):

const span = appInsights.startSpan('operation', options);

Using Tracer API (for organizing by service):

const tracer = appInsights.trace.getTracer('my-service');
const span = tracer.startSpan('operation', options);

Using startActiveSpan (for automatic context management):

appInsights.startActiveSpan('operation', (span) => {
    // Work with automatic context and lifecycle management
});

The direct startSpan method is recommended for most scenarios. Use tracers when you need to organize spans by service name.

API Compatibility

This implementation provides an OpenTelemetry-compatible tracing API based on OpenTelemetry API v1.9.0 specifications:

Scope: Only tracing APIs are implemented. This is not a complete OpenTelemetry SDK - metrics and logs APIs are not included.

Best Practices

  1. Use startActiveSpan for most scenarios - Provides automatic lifecycle management
  2. Always end spans - Either manually or via startActiveSpan
  3. Set span status - Indicate success/failure explicitly with status codes
  4. Use descriptive names - Span names should clearly identify operations
  5. Add relevant attributes - Enrich spans with contextual information
  6. Use service-specific tracers - Organize telemetry by service/component

Common Patterns

Error Handling

const span = tracer.startSpan('risky-operation');
try {
    await performOperation();
    span.setStatus({ code: SpanStatusCode.OK });
} catch (error) {
    span.setStatus({ 
        code: SpanStatusCode.ERROR,
        message: error.message 
    });
    span.setAttribute('error', true);
    span.setAttribute('error.message', error.message);
    throw error;
} finally {
    span.end();
}

Async Operations

tracer.startActiveSpan('async-work', async (span) => {
    span.setAttribute('started', Date.now());
    
    const result = await doAsyncWork();
    
    span.setAttribute('completed', Date.now());
    return result;
});

Background Tasks

import { withSpan } from '@microsoft/applicationinsights-core-js';

const span = tracer.startSpan('background-task');
withSpan(appInsights.core, span, async () => {
    // All nested operations inherit this span context
    await processBackgroundWork();
});
span.end();

Troubleshooting

Spans Not Creating Telemetry

Missing Parent-Child Relationships

Performance Issues

Additional Resources

Support and Feedback

For issues, questions, or feedback:


Learn about startActiveSpan for the recommended way to create spans