Instrumenting .NET Apps with OpenTelemetry
Instrument Using a Library
We will go through a working example of a .NET application auto-instrumented with OpenTelemetry. To keep things simple, we will create a basic “Hello World” web application, instrument it with OpenTelemetry library to generate trace data and send it to an OpenTelemetry Collector. The Collector will then export the trace data to the Wavefront proxy which will eventually export the trace data to our UI.
Prerequisites
- A VMware Aria Operations for Applications account (formerly known as Tanzu Observability by Wavefront) account, which gives you access to a cluster.
- Clone the OpenTelemetry Examples repository.
- Install the Wavefront proxy.
Note: When running the Wavefront proxy:- Make sure that the
WAVEFRONT_PROXY_ARGS
environment variable contains--otlpGrpcListenerPorts 4317
. - And expose the OpenTelemetry port via
-p 4317:4317
.
- Make sure that the
- Set up an OpenTelemetry Collector:
- Download the
otelcol-contrib
binary from the latest release of the OpenTelemetry Collector project. - In the same directory, create a file named
otel_collector_config.yaml
. - Copy the configurations in the preconfigured YAML file to the file you just created. For details on OpenTelemetry configurations, see OpenTelemetry Collector Configuration.
- On your console, navigate to the directory you downloaded in the step above and run the following command to start OpenTelemetry Collector:
./otelcol-contrib --config otel_collector_config.yaml
- Download the
Step 1: Get our example application
The instrumentation works with any application, for this walk through we will refer to the following simple application. Our example application is a locally hosted server that responds with “Hello, World!“ every time we access it.
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Let’s save this file as Program.cs
.
Step 2: Installing OpenTelemetry Components
Several libraries complement the .NET OpenTelemetry implementation that makes integration straightforward. For instrumenting tracing in ASP.NET Core, we use OpenTelemetry.Instrumentation.AspNetCore . In our service, we have used the following packages:
- OpenTelemetry.Exporter.OpenTelemetryProtocol: To export our traces to our OpenTelemetry Collector using OpenTelemetry
Protocol (OTLP).
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.1.0
- OpenTelemetry.Instrumentation.AspNetCore: To collect telemetry about incoming web requests.
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --version 1.0.0-rc8
- OpenTelemetry.Instrumentation.Http: To collect telemetry about outgoing web requests.
dotnet add package OpenTelemetry.Instrumentation.Http --version 1.0.0-rc8
- OpenTelemetry.Extensions.Hosting: To register the .NET OpenTelemetry provider.
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.0.0-rc8
Step 3: Configure the Trace Provider
Now we can enable the instrumentation with a single block of code in our startup to:
- Add a trace provider for OpenTelemetry
- Set the service name we want to appear in the trace. Note: change the service-name/application as per application’s requirements.
- Add the ASP.NET Core instrumentation
- Add an exporter using the OpenTelemetry protocol (OTLP) over gRPC pointing to the OpenTelemetry Collector instance
The code looks like:
var resourceList = new List<KeyValuePair<string, object>>();
resourceList.Add(new KeyValuePair<string, object>
("application", "otel-otlp-.net-app"));
builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =>
{
tracerProviderBuilder.AddAspNetCoreInstrumentation();
tracerProviderBuilder.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService("otel-otlp-.net-service").AddAttributes(resourceList));
tracerProviderBuilder.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("http://localhost:4317");
options.ExportProcessorType = ExportProcessorType.Simple;
});
});
That’s all the coding we need! The libraries we used above provide auto-instrumentation of all the incoming and outgoing web requests.
Step 4: Run our application
The collector is now running and listening to incoming traces on port 4317.
Our next step is to start our application either from the CLI or from our IDE. All that is left for us to do at this
point is to visit localhost
and refresh the page, triggering our app to generate and emit a trace of
that transaction. When the trace data collected from the OpenTelemetry collector are ingested, we can examine them in our user interface.
Manual-Instrumentation
Getting all our web requests instrumented was super simple with auto-instrumentation. But there might be lots going on in our services, and it would be helpful if we broke the span down into parts for finer-grain tracing. To do this, we can add additional spans manually over sections of the code.
Prerequisites
- An Aria Operations for Applications (formerly known as Tanzu Observability by Wavefront) account, which gives you access to a cluster.
- Clone the OpenTelemetry Examples repository.
- Install the Wavefront proxy.
Note: When running the Wavefront proxy:- Make sure that the
WAVEFRONT_PROXY_ARGS
environment variable contains--otlpGrpcListenerPorts 4317
. - And expose the OpenTelemetry port via
-p 4317:4317
.
- Make sure that the
- Set up an OpenTelemetry Collector:
- Download the
otelcol-contrib
binary from the latest release of the OpenTelemetry Collector project. - In the same directory, create a file named
otel_collector_config.yaml
. - Copy the configurations in the preconfigured YAML file to the file you just created. For details on OpenTelemetry configurations, see OpenTelemetry Collector Configuration.
- On your console, navigate to the directory you downloaded in the step above and run the following command to start OpenTelemetry Collector:
./otelcol-contrib --config otel_collector_config.yaml
- Download the
Step 1: Get our example application
Locate the WebApp
web-application in the DOTNET-example
directory.
Step 2: Installing OpenTelemetry Components
Note: Follow the Step 2
mentioned in the Auto-Instrumentation
section.
Step 3: Configure the Trace Provider
Note: Follow the Step 3
mentioned in the Auto-Instrumentation
section.
Step 4: Add a tracer, create a span
- System.Diagnostics.ActivitySource represents
an OpenTelemetry Tracer
var activitySource = new ActivitySource("MyApplicationActivitySource");
- System.Diagnostics.Activity represents
an OpenTelemetry Span
using (var activity = activitySource.StartActivity("Get some data")){}
- add some info to the activity using
AddTag
. This data will be exported to Tanzu Observability.activity?.AddTag("sampleTag", "someTag");
- add baggage using
AddBagage
. Baggage will flow to child activities. This could be useful to flow a correlation id to all child activities, even the ones started on other services.activity?.AddBaggage("sampleBaggage", "someBaggage");
Step 5: Run our application
Run the below commands to start our application either from the CLI.
cd DOTNET-example
dotnet run --project Web-App
All that is left for us to do at this point is to visit http://localhost:5114
and refresh the page, triggering
our app to generate and emit a trace of that transaction. When the trace data collected from the OpenTelemetry collector
are ingested, we can examine them in our user interface.