13 KiB
OpenTelemetry .NET API
- Installation
- Introduction
- Introduction to OpenTelemetry .NET Tracing API
- Instrumenting a library/application with .NET Activity API
- Instrumenting a library/application with OpenTelemetry.API Shim
- References
Installation
dotnet add package OpenTelemetry.Api
Introduction
Application developers and library authors use OpenTelemetry API to instrument their application/library. The API only surfaces necessary abstractions to instrument an application/library. It does not address concerns like how telemetry is exported to a specific telemetry backend, how to sample the telemetry, etc. The API consists of Tracing API, Metrics API, Context and Propagation API, and a set of semantic conventions.
Tracing API
Tracing API allows users to generate Spans, which represent a single operation within a trace. Spans can be nested to form a trace tree. Each trace contains a root span, which typically describes the entire operation and, optionally one or more sub-spans for its sub-operations.
Metrics API
Metrics API allows users to capture measurements about the execution of a computer program at runtime. The Metrics API is designed to process raw measurements, generally with the intent to produce continuous summaries of those measurements.
Introduction to OpenTelemetry .NET Tracing API
.NET runtime had Activity class for a long time, which was meant to be used
for tracing purposes and represents the equivalent of the OpenTelemetry
Span.
OpenTelemetry .NET is reusing the existing Activity and associated classes to
represent the OpenTelemetry Span. This means, users can instrument their
applications/libraries to emit OpenTelemetry compatible traces by using just
the .NET Runtime.
The Activity and associated classes are shipped as part of
System.Diagnostics.DiagnosticSource nuget package. Version 5.0.0 of this
package contains improvements to Activity class which makes it more closely
aligned with OpenTelemetry API
specification.
Even though Activity enables all the scenarios OpenTelemetry supports, users
who are already familiar with OpenTelemetry terminology may find it easy to
operate with that terminology. For instance, StartSpan may be preferred over
StartActivity. To help with this transition, the OpenTelemetry.API package
has shim
classes to wrap around the .NET Activity classes.
The shim exist only in the API. OpenTelemetry SDK for .NET will be operating
entirely with Activity only. Irrespective of whether shim classes or
Activity is used for instrumentation, the end result would be same. i.e
Processors/Exporters see the same data.
Instrumenting a library/application with .NET Activity API
Basic usage
As mentioned in the introduction, the instrumentation API for OpenTelemetry
.NET is the .NET Activity API. Guidance for instrumenting using this API is
documented fully in the TBD(dotnet activity user guide link), but is described
here as well.
-
Install the
System.Diagnostics.DiagnosticSourcepackage version 5.0.0-preview.7.20364.11 or above to your application or library.<ItemGroup> <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="5.0.0-preview.7.20364.11" /> </ItemGroup> -
Create an
ActivitySource, providing the name and version of the library/application being instrumented.ActivitySourceinstance is typically created once and is reused throughout the application/library.static ActivitySource activitySource = new ActivitySource( "companyname.product.library", "semver1.0.0");The above requires import of the
System.Diagnosticsnamespace. -
Use the
ActivitySourceinstance from above to createActivityinstances, which represent a single operation within a trace. The parameter passed is theDisplayNameof the activity.var activity = activitySource.StartActivity("ActivityName");If there are no listeners interested in this activity, the activity above will be null. Ensure that all subsequent calls using this activity is protected with a null check.
-
Populate activity with tags following the OpenTelemetry semantic conventions. It is highly recommended to check
activity.IsAllDataRequested, before populating any tags which are not readily available.activity?.SetTag("http.method", "GET"); if (activity?.IsAllDataRequested ?? false) { activity.SetTag("http.url", "http://www.mywebsite.com"); } -
Perform application/library logic.
-
Stop the activity when done.
activity?.Stop();Alternately, as
ActivityimplementsIDisposable, it can be used with ausingblock, which ensures activity gets stopped upon disposal. This is shown below.using (var activity = activitySource.StartActivity("ActivityName") { activity?.SetTag("http.method", "GET"); } // Activity gets stopped automatically at end of this block during dispose.
The above showed the basic usage of instrumenting using Activity. The
following sections describes more features.
Activity creation options
Basic usage example above showed how StartActivity method can be used to
start an Activity. The started activity will automatically becomes the
Current activity. It is important to note that the StartActivity returns
null, if no listeners are interested in the activity to be created. This
happens when the final application does not enable OpenTelemetry, or when
OpenTelemetry samplers chose not to sample this activity.
StartActivity has many overloads to control the activity creation.
-
ActivityKindActivityhas a property calledActivityKindwhich represents OpenTelemetry SpanKind. The default value will beInternal.StartActivityallows passing theActivityKindwhile starting anActivity.var activity = activitySource.StartActivity("ActivityName", ActivityKind.Server); -
Parent using
ActivityContextActivityContextrepresents the OpenTelemetry SpanContext. While starting a newActivity, the currently activeActivityis automatically taken as the parent of the new activity being created.StartActivityallows passing explicitActivityContextto override this behavior.var parentContext = new ActivityContext( ActivityTraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c"), ActivitySpanId.CreateFromString("b7ad6b7169203331"), ActivityTraceFlags.None); var activity = activitySource.StartActivity( "ActivityName", ActivityKind.Server, parentContext);As
ActivityContextfollows the W3C Trace-Context, it is also possible to provide the parent context as a single string matching thetraceparentheader of the W3C Trace-Context. This is shown below.var activity = activitySource.StartActivity( "ActivityName", ActivityKind.Server, "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"); -
Initial Tags
TagsinActivityrepresents the OpenTelemetry Span Attributes. Earlier sample showed the usage ofSetTagmethod ofActivityto add tags. It is also possible to provide an initial set of tags during activity creation, as shown below.var initialTags = new List<KeyValuePair<string, string>>(); initialTags.Add(new KeyValuePair<string, string>("tag1", "tagValue1")); initialTags.Add(new KeyValuePair<string, string>("tag2", "tagValue2")); var activity = activitySource.StartActivity( "ActivityName", ActivityKind.Server, "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", initialTags);The above requires import of the
System.Collections.Genericnamespace. -
Activity Links
Apart from the parent-child relation, activities can be linked using
ActivityLinkswhich represent the OpenTelemetry Links. The linked activities must be provided during the creation time, as shown below.var activityLinks = new List<ActivityLink>(); var linkedContext1 = new ActivityContext( ActivityTraceId.CreateFromString("0af7651916cd43dd8448eb211c80319c"), ActivitySpanId.CreateFromString("b7ad6b7169203331"), ActivityTraceFlags.None); var linkedContext2 = new ActivityContext( ActivityTraceId.CreateFromString("4bf92f3577b34da6a3ce929d0e0e4736"), ActivitySpanId.CreateFromString("00f067aa0ba902b7"), ActivityTraceFlags.Recorded); activityLinks.Add(new ActivityLink(linkedContext1)); activityLinks.Add(new ActivityLink(linkedContext2)); var activity = activitySource.StartActivity( "ActivityWithLinks", ActivityKind.Server, default(ActivityContext), initialTags, activityLinks);Note that
Activityabove is created withdefault(ActivityContext)parent, which makes it child of implicitActivity.Currentor orphan if there is noCurrent.
Adding Events
It is possible to add
event
with Activity using the AddEvent method as shown below.
activity?.AddEvent(new ActivityEvent("sample activity event."));
Apart from providing name, timestamp and attributes can be provided by using
corresponding overloads of ActivityEvent.
Setting Status
OpenTelemetry defines a concept called
Status
to be associated with Activity. There is no Status class in .NET, and hence
Status is set to an Activity using the following special tags
otel.status_code is the Tag name used to store the Status Canonical
Code.
otel.status_description is the Tag name used to store the optional
Description
Example:
activity?.SetTag("otel.status_code", "status canonical code");
activity?.SetTag("otel.status_description", "status description");
Instrumenting a library/application with OpenTelemetry.API Shim
This section to be filled after shim is shipped.