.NET Framework instrumentation configuration

OpenTelemetry supports both .NET and .NET Framework (an older Windows-based .NET implementation).

If you’re already using the modern, cross-platform implementation of .NET, you can skip this article.

ASP.NET Initialization

Initialization for ASP.NET is a little different than for ASP.NET Core.

First, install the following NuGet packages:

Next, modify your Web.Config file to add a required HttpModule:

<system.webServer>
    <modules>
        <add
            name="TelemetryHttpModule"
            type="OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule,
                OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule"
            preCondition="integratedMode,managedHandler" />
    </modules>
</system.webServer>

Finally, initialize ASP.NET instrumentation in your Global.asax.cs file along with other OpenTelemetry initialization:

using OpenTelemetry;
using OpenTelemetry.Trace;

public class WebApiApplication : HttpApplication
{
    private readonly TracerProvider _tracerProvider;

    protected void Application_Start()
    {
        this.tracerProvider = Sdk.CreateTracerProviderBuilder()
            .AddAspNetInstrumentation()
            
            // Other configuration, like adding an exporter and setting resources
            .AddConsoleExporter()
            .AddSource("my-service-name")
            .SetResourceBuilder(
                ResourceBuilder.CreateDefault()
                    .AddService(serviceName: "my-service-name", serviceVersion: "1.0.0"))

            .Build();
    }

    protected void Application_End()
    {
        _tracerProvider?.Dispose();
    }
}

Advanced ASP.NET configuration

ASP.NET instrumentation can be configured to change the default behavior.

Filter

ASP.NET instrumentation collects all incoming http requests by default. However, you can filter incoming requests by using the Filter method in AspNetInstrumentationOptions. This works similar to a LINQ Where clause, where only requests that match a condition will be collected.

The following code snippet shows how to use Filter to only allow GET requests.

this.tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddAspNetInstrumentation(
        (options) => options.Filter =
            (httpContext) =>
            {
                // only collect telemetry about HTTP GET requests
                return httpContext.Request.HttpMethod.Equals("GET");
            })
    .Build();

Filtering happens at an early stage, and is different from Sampling, which occurs after data has been collected. Filtering will limit what gets collected in the first place.

Enrich

If you have data that you’d like to have added to every Activity that’s generated by OpenTelemetry, you can use the Enrich method.

The Enrich action is called only when activity.IsAllDataRequested is true. It contains the Activity created, the name of the event, and the raw object

The following code snippet shows how to add additional tags using Enrich.

this.tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddAspNetInstrumentation((options) => options.Enrich
        = (activity, eventName, rawObject) =>
    {
        if (eventName.Equals("OnStartActivity"))
        {
            if (rawObject is HttpRequest httpRequest)
            {
                activity?.SetTag("physicalPath", httpRequest.PhysicalPath);
            }
        }
        else if (eventName.Equals("OnStopActivity"))
        {
            if (rawObject is HttpResponse httpResponse)
            {
                activity?.SetTag("responseType", httpResponse.ContentType);
            }
        }
    })
    .Build();

See Add tags to an Activity for annotating trace data more generally.

RecordException

ASP.NET instrumentation automatically sets a given Activity’s status to Error if an unhandled exception is thrown.

You can also set the RecordException property to true, which will store an exception on the Activity itself as an ActivityEvent.

Next steps

After you have observability generated automatically with instrumentation libraries, you may want to add manual instrumentation to collect custom telemetry data.

You’ll also want to configure an appropriate exporter to export your telemetry data to one or more telemetry backends.