APM Tips

Application Insights

Application Insights SDK vs the OpenTelemetry Distro: which to use and how to migrate

Updated · 6 min read · By APM Tips editorial team

For a new .NET, Node.js or Python app, Microsoft recommends the Microsoft OpenTelemetry Distro; apps already on the Azure Monitor OpenTelemetry Distro need no action, and Java uses the Azure Monitor OpenTelemetry Distro through its agent. For an app on the classic .NET SDK 2.x, which retires on March 31, 2027, the shortest path is SDK 3.x, which keeps TelemetryClient but runs on OpenTelemetry; the alternative is a clean move to the Distro. Both write the same Application Insights tables, so most queries and dashboards survive, with differences in sampling, names and custom dimensions to check.

Application Insights now has two current instrumentation paths for .NET and Node.js, and the names make it easy to confuse them. This guide sorts out which is which, what each one changes, and how to move without losing the queries and alerts you rely on.

The current paths

PathPackagesKeeps the classic APIBest for
Microsoft OpenTelemetry DistroMicrosoft.OpenTelemetry, @microsoft/opentelemetry, microsoft-opentelemetryNo; OpenTelemetry APIsNew apps; teams standardising on OpenTelemetry
Application Insights SDK 3.xMicrosoft.ApplicationInsights* 3.x, applicationinsights@^3Mostly (TelemetryClient, TrackEvent, GetMetric)Existing 2.x apps; classic ASP.NET on .NET Framework
Azure Monitor OpenTelemetry DistroAzure.Monitor.OpenTelemetry.AspNetCore, @azure/monitor-opentelemetry, azure-monitor-opentelemetryNoApps already using it; Java (agent or native)

All three use the Azure Monitor exporter underneath and write the same Application Insights tables. Microsoft’s runtime floors for the Distro are Node.js 22, Python 3.10, and for .NET a supported runtime (the package targets net8.0 and netstandard2.0); Java needs Java 8 or later.

Don’t combine them. Microsoft says not to initialize an OpenTelemetry distro alongside SDK 3.x, not to initialize both distros in one app, and not to mix 2.x and 3.x packages.

Classic SDK 2.x

The status of the classic SDKs, as Microsoft and its update notices state it:

  • .NET 2.x: deprecated, retires on March 31, 2027. The last 2.x release is 2.23.0.
  • Node.js 2.x: retired.
  • Java 2.x: retired on September 30, 2025; the 3.x agent replaces it.
  • Python (OpenCensus): retired on September 30, 2024.
  • Instrumentation-key-only configuration: support for ikey ingestion ended on March 31, 2025; use connection strings.

Retirement ends fixes and support. And the extension points a 2.x app relies on (initializers, processors, channels, modules) don’t exist in the newer paths, so the move is a project rather than a package bump. Plan it before you need a fix.

Concept map: 2.x to OpenTelemetry

Classic 2.xSDK 3.xMicrosoft OpenTelemetry Distro
TrackRequest, request moduleKept; requests are server spansActivity with ActivityKind.Server, or framework instrumentation
TrackDependency, DependencyCollectorKept; built-in HTTP and SQL collectionActivity with Client; bundled HttpClient, SqlClient, Azure SDK
TrackTrace, ILogger providerILogger (TrackTrace routes to it)ILogger
TrackEventKept (no metrics dictionary)ILogger with microsoft.custom_event.name
GetMetric, TrackMetricSimplified GetMetric; OpenTelemetry name rulesMeter: Counter, Histogram, Gauge
TrackPageViewRemovedJavaScript SDK in the browser
ITelemetryInitializerOpenTelemetry processor, GlobalPropertiesBaseProcessor<Activity>, resource attributes
ITelemetryProcessor (filtering)OpenTelemetry processorProcessor or sampler
ITelemetryChannel, ServerTelemetryChannelAzure Monitor exporter (StorageDirectory)Azure Monitor exporter (StorageDirectory)
Adaptive samplingTracesPerSecond (default 5) or SamplingRatioTracesPerSecond (default 5) or SamplingRatio
Cloud.RoleName, Component.Versionservice.name, service.versionservice.name, service.version
ApplicationInsights.configFlat applicationinsights.config, appsettings.jsonEnvironment variables and options
DeveloperModeRemovedExportTarget.Console for local checks
Operation ID, parent IDTrace ID, span IDTrace ID, span ID

The guides on initializers and processors, channels and exporters, sampling and custom metrics go through each row in detail.

Today: choosing between SDK 3.x and the Distro

Choose SDK 3.x when the app calls TelemetryClient in many places, when it’s classic ASP.NET on .NET Framework (the Distro’s built-in request instrumentation is for ASP.NET Core), or when you want the migration in two steps: first runtime, later APIs. Microsoft describes 3.x as the way to minimise re-instrumentation; most Track* calls keep working through a mapping layer that emits OpenTelemetry signals.

Choose the Distro for new apps, for services where you’d like the option to export elsewhere (the .NET Distro can export to Azure Monitor and an OTLP endpoint at once, ExportTarget.AzureMonitor | ExportTarget.Otlp, though Microsoft notes it doesn’t officially support the OTLP exporter itself), and when you’re rewriting custom telemetry anyway.

What you give up, on either path: per-type sampling (one rate covers requests and dependencies, though logs can follow traces), TrackPageView in .NET, and every classic initializer, processor and module, which have to be rewritten. Microsoft also lists known issues of the OpenTelemetry exporters: the operation name is missing from dependency telemetry, which affects the Failures and Performance views for dependencies, and the device model is missing from requests and dependencies.

Migration steps for a .NET 2.x app

To SDK 3.x:

  1. Remove the packages with no 3.x version: WindowsServer.TelemetryChannel, DependencyCollector, EventCounterCollector, PerfCounterCollector, WindowsServer, Microsoft.Extensions.Logging.ApplicationInsights, Log4NetAppender, TraceListener, DiagnosticSourceListener, EtwCollector, EventSourceListener. Check third-party packages that depend on 2.x, such as the Serilog sink.
  2. Upgrade every remaining Application Insights package to 3.x together.
  3. Fix the breaking changes: a full connection string is required (3.x can fail at startup without one); TelemetryConfiguration.Active and new TelemetryClient() become TelemetryConfiguration.CreateDefault(); metric names must start with a letter and use only letters, digits, _ . - /; TrackPageView and the metrics-dictionary overloads go.
  4. Rewrite initializers and processors as OpenTelemetry processors, and replace EnableAdaptiveSampling with TracesPerSecond or SamplingRatio.
  5. Validate with self-diagnostics and a console exporter before relying on Azure Monitor.

To the Distro: remove the Application Insights packages, add Microsoft.OpenTelemetry, register it at startup, and move custom telemetry to ActivitySource, Meter and ILogger.

The startup change for an ASP.NET Core app moving from 2.x to the Distro:

// Before (2.x)
builder.Services.AddApplicationInsightsTelemetry();

// After (Microsoft OpenTelemetry Distro)
builder.UseMicrosoftOpenTelemetry(options =>
{
    options.Exporters = ExportTarget.AzureMonitor; // reads APPLICATIONINSIGHTS_CONNECTION_STRING
});

Node.js offers the same two choices: a clean install of @microsoft/opentelemetry (call useMicrosoftOpenTelemetry() before loading the libraries you want instrumented), or npm install applicationinsights@^3 to keep the classic API on OpenTelemetry. Python apps on OpenCensus uninstall the OpenCensus libraries, remove them from the code, and set up microsoft-opentelemetry. Java apps replace the 2.x SDK with the 3.x agent; 2.x initializers and processors don’t run under it.

Keep queries, dashboards and alerts working

Table and column names don’t change: requests are still in requests (AppRequests), with the same operation_Id and customDimensions. What changes is what’s inside them, so before switching production, run the new build in one environment and compare by application_Version:

union requests, dependencies
| where timestamp > ago(1d)
| summarize items = sum(itemCount), names = dcount(name) by itemType, application_Version, sdkVersion

Check four things. Names: request names follow the route template, and unmatched routes become just the method, as in how requests are named. Custom dimension keys: attribute names from OpenTelemetry instrumentation can differ from 2.x property names, so update queries that filter on them. Counts: sampling changes from adaptive to rate-limited at five traces per second, so alerts built on count() need sum(itemCount). Role names: set service.name so cloud_RoleName matches what dashboards expect.

Troubleshooting

SymptomLikely causeFix
Duplicate telemetry after migratingTwo pipelines active (2.x plus Distro, or two distros)Keep one
3.x app won’t startNo connection stringSet APPLICATIONINSIGHTS_CONNECTION_STRING
Custom properties goneInitializers don’t run in 3.x or the DistroRewrite as processors
Metric missing after 3.x upgradeName not valid OpenTelemetry syntaxRename the metric
Dependency rows lack operation nameKnown exporter issueGroup by operation_Id or the parent request instead
Volume or counts changedNew sampling defaultsCheck itemCount; tune TracesPerSecond

Queries for this topic

From the KQL library: explained queries for the Application Insights tables, ready to copy.

  • Sampling rate in effect, per telemetry type

    requestsdependenciespageViewsbrowserTimingsexceptionstracescustomEventsavailabilityResults cost

    Returns: One row per telemetry type with the rows stored, the items they stand for, and the percentage of items kept by sampling over the last 24 hours.

  • Dependency calls per request, by operation

    requestsdependencies dependencies

    Returns: One row per request operation with its request count, the dependency calls made under that operation name and the average calls per request, chattiest first.

Frequently asked questions

Is the Application Insights SDK deprecated?

The .NET Classic API SDK 2.x is deprecated and retires on March 31, 2027; the Node.js 2.x SDK is already retired. The classic packages continue as SDK 3.x, built on OpenTelemetry, for .NET and Node.js. The Java 2.x SDK was retired on September 30, 2025, and OpenCensus for Python on September 30, 2024.

Do I have to move to the Microsoft OpenTelemetry Distro if I use the Azure Monitor OpenTelemetry Distro?

No. Microsoft's guidance for apps already on the Azure Monitor OpenTelemetry Distro is "No action needed". Don't initialize both distros in the same app. Because both use the same OpenTelemetry APIs, switching later is mostly a package and startup change.

Will my KQL queries and dashboards still work after migrating?

Mostly. Both paths write the same requests, dependencies, traces, exceptions and customMetrics tables. Check request and dependency names, custom dimension keys, role names and counts: sampling defaults change to five traces per second, so weight counts with itemCount.

Sources, checked

  1. Enable OpenTelemetry in Application Insights (which path to use)learn.microsoft.com · checked
  2. Migrate Application Insights Classic API SDKs to OpenTelemetrylearn.microsoft.com · checked
  3. Monitor .NET and Node.js applications with Application Insights (Classic API 2.x)learn.microsoft.com · checked
  4. Migration guidance from 2.x to 3.x (ApplicationInsights-dotnet)github.com · checked
  5. Configure OpenTelemetry in Application Insightslearn.microsoft.com · checked
  6. Add and modify OpenTelemetry in Application Insightslearn.microsoft.com · checked
  7. Troubleshoot OpenTelemetry issues in .NET (known issues)learn.microsoft.com · checked
  8. Microsoft.OpenTelemetry (Microsoft OpenTelemetry Distro for .NET, README)github.com · checked