All Products
Search
Document Center

Application Real-Time Monitoring Service:Report .NET trace data with OpenTelemetry

Last Updated:Mar 11, 2026

Instrument your .NET application with OpenTelemetry and report trace data to Managed Service for OpenTelemetry. After traces flow in, you can view application topology, traces, abnormal and slow transactions, and SQL analysis in the Application Real-Time Monitoring Service (ARMS) console.

OpenTelemetry supports three instrumentation approaches for .NET. Start with automatic instrumentation. Add manual instrumentation if automatic does not cover all frameworks in your application or if you need custom business spans.

ApproachBest for.NET version
AutomaticQuick setup with zero code changes.NET 6+ (.NET Framework not supported)
ManualFull control over spans and trace context.NET 5+, .NET Core 2.0+, .NET Framework 4.6.1+
Combined (recommended)Automatic framework traces plus custom business spans.NET 6+ for auto; see manual requirements for custom spans

Sample code

Download the complete sample code from dotnet-demo.

Automatic instrumentation

Automatic instrumentation uses the OpenTelemetry .NET agent to capture traces without code changes. It supports .NET 6 and later. .NET Framework is not supported.

For a full list of automatically instrumented frameworks, see Available instrumentations in the OpenTelemetry documentation.

Step 1: Create a sample web application

  1. Create a new ASP.NET Core project and build it:

       mkdir dotnet-simple-demo
       cd dotnet-simple-demo
       dotnet new web
       dotnet build
  2. Replace the contents of Properties/launchSettings.json with the following configuration:

       {
         "$schema": "http://json.schemastore.org/launchsettings.json",
         "profiles": {
           "http": {
             "commandName": "Project",
             "dotnetRunMessages": true,
             "launchBrowser": true,
             "applicationUrl": "http://localhost:8080",
             "environmentVariables": {
               "ASPNETCORE_ENVIRONMENT": "Development"
             }
           }
         }
       }

Step 2: Install the automatic instrumentation agent

Download and run the installation script:

curl -L -O https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/otel-dotnet-auto-install.sh
./otel-dotnet-auto-install.sh

Step 3: Configure environment variables and run the application

Set the required environment variables, source the instrumentation script, and start the application.

Replace the following placeholders with your actual values:

PlaceholderDescriptionExample
<service-name>A name to identify your application in ARMSmy-dotnet-app
<endpoint>The gRPC endpoint from the Prerequisites sectionhttp://tracing-analysis-dc-hz.aliyuncs.com:8090
<token>The authentication token from the Prerequisites sectionabc123_your_token
export OTEL_TRACES_EXPORTER=otlp \
  OTEL_METRICS_EXPORTER=none \
  OTEL_LOGS_EXPORTER=none \
  OTEL_SERVICE_NAME=<service-name> \
  OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
  OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> \
  OTEL_EXPORTER_OTLP_HEADERS="Authentication=<token>"

. $HOME/.otel-dotnet-auto/instrument.sh
dotnet run

Step 4: Verify trace reporting

Send a request to the application to generate traces:

curl localhost:8080/

The automatic instrumentation agent captures the request and reports the trace to Managed Service for OpenTelemetry. To verify that traces arrived, see View monitoring data.

For additional configuration options such as resource attributes, sampler settings, and propagation, see Configuration and settings in the OpenTelemetry documentation.

Manual instrumentation

Manual instrumentation gives full control over which operations produce spans. Use this approach when automatic instrumentation does not cover your framework or when you need to trace custom business logic.

Step 1: Add OpenTelemetry packages

Navigate to the dotnet-demo/opentelemetry-demo/manual-demo directory and add the required NuGet packages:

dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Exporter.Console       # Optional: export to console for debugging
dotnet add package OpenTelemetry.Extensions.Hosting

Step 2: Create the tracing configuration

Create OpentelemetryExporterDemo.cs with a TracerProvider that exports spans over HTTP to your Managed Service for OpenTelemetry endpoint.

Replace <endpoint> with the HTTP endpoint from the Prerequisites section.

using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
using OpenTelemetry.Exporter;

namespace Demo
{
    internal static class OpentelemetryExporterDemo
    {
        internal static void Run()
        {
            Console.WriteLine("otlp running");
            // Specify the service name that appears in ARMS.
            var serviceName = "otlp-test";
            using var tracerProvider = Sdk.CreateTracerProviderBuilder()
                .AddSource(serviceName)
                .SetResourceBuilder(
                ResourceBuilder.CreateDefault().AddService(serviceName))
                .AddOtlpExporter(opt =>
                                 {
                                     // Set the HTTP endpoint for trace export.
                                     opt.Endpoint = new Uri("<endpoint>");
                                     opt.Protocol = OtlpExportProtocol.HttpProtobuf;
                                 })
                .AddConsoleExporter() // Optional: prints spans to console for debugging.
                .Build();
            for(int i = 0; i<10; i++)
            {
                var MyActivitySource = new ActivitySource(serviceName);
                using var activity = MyActivitySource.StartActivity("SayHello");
                activity?.SetTag("bar", "Hello World");
            }
        }
    }
}

Step 3: Update the entry point

Modify Program.cs to call the tracing demo:

using System.Diagnostics;
using System.Net.Http;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;


namespace Demo
{
    public class Otlp
    {
        public static void Main(string[] args)
        {
            OpentelemetryExporterDemo.Run();
        }
    }
}

Step 4: Run and verify

dotnet run

The application creates 10 sample spans and exports them to Managed Service for OpenTelemetry. To verify that traces arrived, see View monitoring data.

Combined automatic and manual instrumentation

This approach combines automatic framework-level instrumentation (for example, ASP.NET Core HTTP traces) with custom spans for business logic. For most production applications, this is the recommended approach.

OpenTelemetry can automatically instrument dozens of .NET frameworks. For a full list, see Traces instrumentations.

Step 1: Create an ASP.NET Core MVC application

Navigate to the dotnet-demo/opentelemetry-demo/auto-demo directory. Replace <your-project-name> with your application name:

mkdir <your-project-name>
cd <your-project-name>
dotnet new mvc

Step 2: Add OpenTelemetry packages

Install the core OpenTelemetry packages and the ASP.NET Core instrumentation library:

dotnet add package OpenTelemetry.Exporter.Console               # Optional: export to console for debugging
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol  # Export over OTLP
dotnet add package OpenTelemetry.Instrumentation.AspNetCore      # Auto-instrument ASP.NET Core

To instrument additional frameworks (such as HttpClient, gRPC, or SQL), add the corresponding OpenTelemetry.Instrumentation.* package. See Traces instrumentations for the full list.

Step 3: Configure OpenTelemetry in Program.cs

Add the following imports at the top of Program.cs:

using System.Diagnostics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

Add the DiagnosticsConfig class at the end of the file. Replace <your-service-name> and <your-host-name> with your actual values:

public static class DiagnosticsConfig
{
    public const string ServiceName = "<your-service-name>";
    public const string HostName = "<your-host-name>";
    public static ActivitySource ActivitySource = new ActivitySource(ServiceName);
}

Add the OpenTelemetry initialization code between builder.Services.AddControllersWithViews() and var app = builder.Build(). Choose one of the following export protocols:

Option A: Export over HTTP

Replace <http_endpoint> with the HTTP endpoint from the Prerequisites section:

// ...
builder.Services.AddOpenTelemetry()
    .WithTracing(tracerProviderBuilder =>
        tracerProviderBuilder
            .AddSource(DiagnosticsConfig.ActivitySource.Name)
            .SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder.CreateDefault()
                .AddAttributes(new Dictionary<string, object> {
                    {"service.name", DiagnosticsConfig.ServiceName},
                    {"host.name",DiagnosticsConfig.HostName}
                }))
            .AddAspNetCoreInstrumentation()
            .AddConsoleExporter() // Optional: prints spans to console for debugging.
            .AddOtlpExporter(opt =>
            {
                opt.Endpoint = new Uri("<http_endpoint>");
                opt.Protocol = OtlpExportProtocol.HttpProtobuf;
            })
     );
// ...

Option B: Export over gRPC

Replace <grpc_endpoint> and <token> with the gRPC endpoint and authentication token from the Prerequisites section:

// ...
builder.Services.AddOpenTelemetry()
    .WithTracing(tracerProviderBuilder =>
        tracerProviderBuilder
            .AddSource(DiagnosticsConfig.ActivitySource.Name)
            .SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder.CreateDefault()
                .AddAttributes(new Dictionary<string, object> {
                    {"service.name", DiagnosticsConfig.ServiceName},
                    {"host.name",DiagnosticsConfig.HostName}
                }))
            .AddAspNetCoreInstrumentation()
            .AddConsoleExporter() // Optional: prints spans to console for debugging.
            .AddOtlpExporter(opt =>
            {
                opt.Endpoint = new Uri("<grpc_endpoint>");
                opt.Headers = "Authentication=<token>";
                opt.Protocol = OtlpExportProtocol.Grpc;
            })
     );
// ...

Complete Program.cs example

// Import required packages.
using System.Diagnostics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);


builder.Services.AddControllersWithViews();

// Initialize OpenTelemetry.
builder.Services.AddOpenTelemetry()
    .WithTracing(tracerProviderBuilder =>
        tracerProviderBuilder
            .AddSource(DiagnosticsConfig.ActivitySource.Name)
            .SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder.CreateDefault()
                .AddAttributes(new Dictionary<string, object> {
                    {"service.name", DiagnosticsConfig.ServiceName},
                    {"host.name",DiagnosticsConfig.HostName}
                }))
            .AddAspNetCoreInstrumentation()
            .AddConsoleExporter() // Optional: prints spans to console for debugging.
            .AddOtlpExporter(opt =>
            {
                // Export over HTTP.
                opt.Endpoint = new Uri("<http_endpoint>");
                opt.Protocol = OtlpExportProtocol.HttpProtobuf;

                // To export over gRPC instead, uncomment the following lines
                // and comment out the HTTP lines above:
                // opt.Endpoint = new Uri("<grpc_endpoint>");
                // opt.Headers = "Authentication=<token>";
                // opt.Protocol = OtlpExportProtocol.Grpc;
            })
     );


var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

// DiagnosticsConfig: replace with your actual service and host names.
public static class DiagnosticsConfig
{
    public const string ServiceName = "<your-service-name>";
    public const string HostName = "<your-host-name>";
    public static ActivitySource ActivitySource = new ActivitySource(ServiceName);
}

Step 4: Run the application

dotnet run

Sample output:

Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5107
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /path/to/<your-project-name>

Step 5: Verify trace reporting

Open the URL from the output (for example, http://localhost:5107) in a browser. If the default ASP.NET Core MVC page loads, the application is running and traces are being reported to Managed Service for OpenTelemetry.

Verification page

To verify that traces arrived, see View monitoring data.

View monitoring data

After you generate trace data, verify that it reaches Managed Service for OpenTelemetry:

  1. Log on to the ARMS console.

  2. In the left-side navigation pane, choose Application Monitoring > Applications.

  3. On the Applications page, find your application by the service name you configured. Click the application name to view trace data, topology, and performance metrics.

If your application appears in the list, trace reporting is working. If it does not appear, wait 1--2 minutes and refresh the page. Trace data may take a short time to process.

The Language column on the Applications page indicates the connection type. The icon icon means the application is connected to Application Monitoring. A hyphen (-) means the application is connected to Managed Service for OpenTelemetry.

Supported frameworks for manual and semi-automatic instrumentation

The following table lists the frameworks supported by OpenTelemetry for manual and semi-automatic .NET instrumentation.

FrameworkWindows .NET FrameworkCross-platform .NET (.NET Core)Supported versionInstrumented library
ASP.NETYesNot supported (MVC and Web API)N/AN/A
ASP.NET CoreN/AYesN/AN/A
AzureYesYesPackages with the Azure. prefix released after October 1, 2021Azure SDK
ElasticsearchYesYesV8.0.0 to V8.10.0 (exclusive). V8.10.0 and later are supported by the Elasticsearch Transport framework.Elastic.Clients.Elasticsearch
Elasticsearch TransportYesYesV0.4.16+Elastic.Transport
Entity Framework CoreN/AYesV6.0.12+Microsoft.EntityFrameworkCore
GraphQLN/AYesV7.5.0+GraphQL
gRPC ClientYesYesV2.52.0 to V3.0.0 (exclusive)Grpc.Net.Client
HttpClientYesYesAll versionsSystem.Net.Http.HttpClient, System.Net.HttpWebRequest
QuartzV4.7.1 and earlier not supportedYesV3.4.0+Quartz
MassTransitN/AYesV8.0.0+MassTransit
MongoDBYesYesV2.13.3 to V3.0.0 (exclusive)MongoDB.Driver.Core
MySQL ConnectorYesYesV2.0.0+MySqlConnector
MySQL DataN/AYesV8.1.0+MySql.Data
NpgsqlYesYesV6.0.0+Npgsql
NServiceBusYesYesV8.0.0+NServiceBus
SQL ClientYesYesMicrosoft.Data.SqlClient V3 not supportedMicrosoft.Data.SqlClient, System.Data.SqlClient, System.Data (shipped with .NET Framework)
StackExchange.RedisN/AYesV2.0.405 to V3.0.0 (exclusive)StackExchange.Redis
WCF ClientYesYesN/AN/A
WCF ServiceYesN/AN/AN/A