Telemetry in ASP.Net Core Web API

Introduction

In the world of software programming, you certainly faced issues related to performance and spent a considerable amount of time looking for the root cause.

Especially when you use third-party libraries and you don't have an idea about how they were developed. To avoid this, you can anticipate the monitoring of your web API and provide the administrators of your services enough information about the state during the execution.

Telemetry is a very rich field. In this article, I will give you the first concepts that will help you implement your telemetry in your Web API

What is telemetry?

Telemetry is the ability of a service to provide accurate data about its performance and the resources that it consumes. This will help to identify issues and make data-driven improvements.

In Asp .net Core API there are several ways to provide data about performance. You can simply do it by exporting your data into Txt files or event log viewer, you can also inspect the calls using the browser debugger. But telemetry will allow you to control your API, analyze exactly the piece of code that you need, and present the data more elegantly with tools that provide clear dashboards. Some of these tools are prometheus, jaeger, Grafana, signoz ...

The way it works is that you should include a telemetry "exporter" in your API, and then it will be able to expose the telemetry data in a usable way by the external tools.

Let's see how to do it.

Prerequisite

  • Visual Studio 2022
  • OpenTelemtry Nuget Packages
  • Jaeger for Windows can be downloaded from the following URL-https://www.jaegertracing.io/download/.

Create a new project

Open Visual Studio 2022 then create a new ASP net core web Api project

Follow the instructions then choose the right installed version of .net core.

I'm using 7.0 but it should work with a lower version

Additional information-

Nuget packages

To be able to use the feature that openTelemtry offers with Jaeger, you need to install some packages related to telemetry.

You can copy and paste the following one to your .csproj and the packages will be restored automatically when you build.

<PackageReference Include="OpenTelemetry" Version="1.2.0-rc4" />
<PackageReference Include="OpenTelemetry.Api" Version="1.2.0-rc4" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.2.0-rc4" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.2.0-rc4" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.2.0-rc4" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.1" />

Call the instrumentation and exporter methods

Once you referenced the needed packages, you need to initialize the OpenTelemetry tracing and instrumentation by doing the following calls in your program.cs

As you can see, we are initializing a Jaeger exporter, which means that our service will expose the telemetry data in a way that Jaeger can understand it

builder.Services.AddOpenTelemetryTracing(options =>
    options.AddConsoleExporter()
        .AddSource(TestTelemetryController.TelemtrySource)
        .SetResourceBuilder(ResourceBuilder.CreateDefault()
            .AddService(TestTelemetryController.TelemtrySource)
            .AddTelemetrySdk())
        .AddHttpClientInstrumentation()
        .AddAspNetCoreInstrumentation()
        .AddJaegerExporter()
);

builder.Services.AddOpenTelemetryMetrics(options =>
    options.AddHttpClientInstrumentation()
        .SetResourceBuilder(ResourceBuilder.CreateDefault()
            .AddService(TestTelemetryController.TelemtrySource)
            .AddTelemetrySdk())
        .AddMeter("Meter1")
        .AddOtlpExporter()
);

Create your controller and trace the calls

Now you can create your controller and monitor the activity of your code.

You can add tags with data to trace the behavior of a specific part in your controller and then you will be able to visualize it in Jaeger due to the Jaeger exporter.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System.Diagnostics;
using System.Diagnostics.Metrics;

namespace TelemtryUsingJaeger.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TestTelemetryController : ControllerBase
    {
        //You can move this into a helper or any other class
        public const string TelemetrySource = "TestTelemetry";

        [HttpGet]
        public void Get()
        {
            //Create the Activity source
            ActivitySource _source = new ActivitySource(TelemetrySource);

            using (var activity = _source.StartActivity("FirstCallActivity"))
            {
                //Add a tag to store the data in the activity
                //For example the time before the current call
                DateTime d1 = DateTime.Now;
                activity?.SetTag("TimeOfCall", d1.ToString());

                //This sleep will simulate the processing of your method
                //It could be a third party that you want to monitor
                Thread.Sleep(1000);
                DateTime d2 = DateTime.Now;
                //Add a tag to store the data in the activity
                //For example the time after the current call
                activity?.SetTag("TimeAfterCall", d2.ToString());
                //A calculation can be added also
                activity?.SetTag("CallDuration", d2 - d1);
            }

            //Do the same previous thing with a second activity
            using (var activity = _source.StartActivity("SecondCallActivity"))
            {
                DateTime d1 = DateTime.Now;
                activity?.SetTag("TimeOfCall", d1.ToString());

                Thread.Sleep(1500);

                DateTime d2 = DateTime.Now;
                activity?.SetTag("TimeAfterCall", d2.ToString());
                activity?.SetTag("CallDuration", d2 - d1);
            }
        }
    }
}

Launch jaeger

When you download Jaeger, you should have the following folder, navigate to it using the command line then launch thejaeger-all-in-one.exe.

If you get a security alert, click "Allow".

Example-hotrod.exe-

You should have the service listening on port16686

Port-

Now go to the browser and typehttp://localhost:16686/search, you should get the Jaeger UI.

Jaeger UI-

Perform a call from the API

Now call the monitored method using your swagger, all the traces that we did in the code should appear in Jaeger

Telemtry using jaeger-

Check Jaeger

Now if you recheck Jaeger, you will find the data related to our API.

JaegerAfterCall-

Let's check in detail the call that has 3 spans and we will see that every span corresponds to an operation that we specified in our code.

Test telemetry-

We can see that the three spans are the main Api call and the two activities that we set explicitly in the code.

We can also the tags that we set in the code with their values

Conclusion

Telemetry is one of the tools that allows you to have a clear visibility of the performance of the technical activities of your API.

If you know other ways to do it feel free to suggest them in the comments