OpenTelemetry Tracing API for .NET

TIP

This document teaches how to use OpenTelemetry .NET API. To learn how to install and configure OpenTelemetry .NET SDK, see Getting started with OpenTelemetry .NETopen in new window.

OpenTelemetry-DotNet

OpenTelemetry-DotNetopen in new window is the .NET implementation of OpenTelemetry. It provides OpenTelemetry Tracing API which you can use to instrument your application with traces.

Activity API

OpenTelemetry API reuses .NET Activity APIopen in new window which existed long before OpenTelemetry was created. Activity API covers all OpenTelemetry requirements but uses slightly different API and terminology.

OpenTelemetry API.NET Activity API
TracerActivitySource
SpanActivity
NoopSpannull activity
SpanContextActivityContext
Span kindActivityKind
AttributeTag
SpanLinkActivityLink
SpanEventActivityEvent
span.IsRecording()activity.IsAllDataRequested

To install Activity API, add the following dependency to your project:

<ItemGroup>
  <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="5.0.1" />
</ItemGroup>

Quickstart

Step 1. Let's instrument the following function:

public string RedisGet(string key) {
    return this.redisDb.StringGet("mykey");
}

Step 2. Wrap the operation with a span:

using System.Diagnostics;

var activitySource = new ActivitySource("app_or_lib_name")

public string RedisGet(string key) {
    using var activity = this.activitySource.StartActivity("RedisGet");

    return this.redisDb.StringGet("mykey");
}
 

 


 



Step 3. Record errors and set status code:

public string RedisGet(string key) {
    using var activity = this.activitySource.StartActivity("RedisGet");

    try {
        return this.redisDb.StringGet("mykey");
    } catch (Exception ex) {
        activity?.RecordException(ex);
        activity?.SetStatus(Status.Error.WithDescription(ex.Message));
    }
}





 
 
 
 

Step 4. Record contextual information with attributes:

public string RedisGet(string key) {
    using var activity = this.activitySource.StartActivity("RedisGet");

    if (activity != null && activity.IsAllDataRequested) {
        activity.SetTag("redis.key", key);
    }

    try {
        return this.redisDb.StringGet("mykey");
    } catch (Exception ex) {
        activity?.RecordException(ex);
        activity?.SetStatus(Status.Error.WithDescription(ex.Message));
    }
}



 
 
 








And that's it! The operation is fully instrumented.

Tracer

To start creating spans, you need a tracer (ActivitySource). You can create a tracer by providing the name and version of the library/application doing the instrumentation:

using System.Diagnostics;

static ActivitySource activitySource = new ActivitySource(
    "app_or_package_name",
    "semver1.0.0");

You can have as many tracers as you want, but usually you need only one tracer for an app or a library. Later, you can use tracer names to identify the instrumentation that produces the spans.

Creating spans

You can create spans using StartActivity. Because StartActivity returns null activity when OpenTelemetry is not enabled or span was not sampled, you need to check for null when working with activities:

var activity = activitySource.StartActivity("operation-name", ActivityKind.Server);

// do something

// End the span when the operation we are measuring is done.
activity?.Stop();

You can also create spans in using blocks to automatically stop the activity in the end of the block:

using (var activity = activitySource.StartActivity("operation-name")
{
    activity?.SetTag("http.method", "GET");
} // activity is automatically stopped during block disposal

Current span

OpenTelemetry stores the active span in a context and saves the context in a pluggable context storage. You can nest contexts inside each other and OpenTelemetry will automatically activate the parent span context when you end the span.

To get the active span from the current context:

// may be null if there is none
var activity = Activity.Current;

Adding span attributes

To record contextual information, you can annotate spans with attributes. For example, an HTTP endpoint may have such attributes as http.method = GET and http.route = /projects/:id.

// To avoid expensive computations, check that span was sampled
// before setting any attributes.
if (activity != null && activity.IsAllDataRequested)
{
    activity.SetTag("http.method", "GET");
    activity.SetTag("http.route", "/projects/:id");
}

You can name attributes as you want, but for common operations you should use semantic attributes convention.

Adding span events

You can annotate spans with events, for example, you can use events to record log messages:

activity?.AddEvent(
    new ActivityEvent(
        "log",
        DateTime.UtcNow,
        new ActivityTagsCollection(
            new Dictionary<string, object>
            {
                { "log.severity", "error" },
                { "log.message", "User not found" },
                { "enduser.id", 123 },
            }
        )
    )
);

Setting status code

You can set error status code to indicate that the operation contains an error:

catch (Exception ex)
{
    activity?.SetStatus(Status.Error.WithDescription(ex.Message));
}

Recording exceptions

OpenTelemetry provides a shortcut to record exceptionsopen in new window which is usually used together with SetStatus:

using (var activity = activitySource.StartActivity("operation-name"))
{
    try
    {
        Func();
    }
    catch (Exception ex)
    {
        activity?.RecordException(ex);
        activity?.SetStatus(Status.Error.WithDescription(ex.Message));
    }
}

OpenTelemetry APM

Uptrace is a OpenTelemetry backendopen in new window that supports distributed tracing, metrics, and logs. You can use it to monitor applications and troubleshoot issues.

Uptrace Overview

Uptrace comes with an intuitive query builder, rich dashboards, alerting rules with notifications, and integrations for most languages and frameworks.

Uptrace can process billions of spans and metrics on a single server and allows you to monitor your applications at 10x lower cost.

In just a few minutes, you can try Uptrace by visiting the cloud demoopen in new window (no login required) or running it locally with Dockeropen in new window. The source code is available on GitHubopen in new window.

What's next?

Last Updated: