DEV Community

Cover image for Monitoring your .NET application with open-source tools | Tutorial
Ankit Anand ✨ for SigNoz

Posted on • Originally published at signoz.io

Monitoring your .NET application with open-source tools | Tutorial

This tutorial was originally posted on SigNoz Blog and is written by Chenna.

C# (pronounced C-Sharp) is a simple, modern, object-oriented, and type-safe programming language. ASP.NET is one of the top frameworks for building modern applications using C#, F#, or Visual Basic.

OpenTelemetry is one of the popular CNCF projects. Some other notable projects under CNCF include Kubernetes, Helm, and Fluentd. The OpenTelemetry project aims to create an open source web standard for instrumenting cloud-native applications.

With cloud computing and containerization, there has been a rapid rise in applications with distributed systems. Distributed architectures like microservices and serverless have many benefits like on-demand scaling, but they also come with operational and troubleshooting complexities.

A robust monitoring and observability framework is needed to simplify complex cloud-native environments. One of the major challenges of setting up this framework is instrumenting a distributed application. OpenTelemetry helps solve this challenge by providing a uniform instrumentation layer. It generates three core signals from applications:

  • Traces: Insights about the traffic across the services
  • Metrics: Insights on performance & resource consumption
  • Logs: How the code is executing with the help of errors/exceptions

OpenTelemetry is used to generate and collect the telemetry data(traces, metrics, and logs), but it does not provide storage and visualization of collected data. OpenTelemetry provides you the freedom to choose a backend analysis tool. And that’s where SigNoz comes into the picture.

SigNoz & OpenTelemetry

SigNoz is a full-stack open-source application monitoring and observability platform
 which can be installed within your infra. It provides metrics monitoring, distributed tracing, exceptions monitoring, and custom dashboards - everything under a single pane of glass. You can also set alerts on your critical metrics to keep yourself notified.

SigNoz is built to natively support OpenTelemerty, thus making it a great choice for the OpenTelemetry backend.

Now let’s get down to see how to instrument a .NET application with OpenTelemetry and then visualize the data with SigNoz.

We will divide the tutorial into the following parts:

  1. Installing SigNoz
  2. Instrumenting a sample ASP.NET 6 MVC web app for traces
  3. Instrumenting .NET application for metrics
  4. Exception Logging

Installing SigNoz

SigNoz can be installed on macOS or Linux computers in just three steps by using a simple installation script.

The install script automatically installs Docker Engine on Linux. However, on macOS, you must manually install Docker Engine before running the install script.

git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy/
./install.sh
Enter fullscreen mode Exit fullscreen mode

You can visit our documentation for instructions on how to install SigNoz using Docker Swarm and Helm Charts.

Deployment Docs

When you are done installing SigNoz, you can access the UI at http://localhost:3301

SigNoz dashboard
SigNoz dashboard - It shows services from a sample app that comes bundled with the application

OpenTelemetry .NET instrumentation for tracing

Step 1: Create new .NET MVC project

dotnet new mvc -n Org.MyWebApp --no-https
Enter fullscreen mode Exit fullscreen mode

Step 2: Install OpenTelemetry Packages

cd Org.MyWebApp
dotnet add package OpenTelemetry.Extensions.Hosting --prerelease
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --prerelease
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --prerelease
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure OpenTelemetry

Note that you need to set the endpoint of SigNoz in this code snippet. If you have installed SigNoz in your local, then the endpoint is http://localhost:4317.

using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

...
builder.Services.AddOpenTelemetryTracing(budiler =>
    {
        budiler
            .AddAspNetCoreInstrumentation()
            .SetResourceBuilder(ResourceBuilder.CreateDefault()
                .AddService("MyWebApp")
                .AddTelemetrySdk()
            )
            .AddOtlpExporter(options =>
            {
                options.Endpoint = new Uri("http://localhost:4317"); // Signoz Endpoint
            });
    });

var app = builder.Build();
...
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the .NET app

dotnet run
Enter fullscreen mode Exit fullscreen mode

Step 5: Monitor traces of your .NET application

Visit application localhost:<port>/ and then visit SigNoz dashboard http://localhost:3301/application to see your .NET application being monitored on the SigNoz dashboard.

Please ensure that you have generated some dummy data by calling your application’s endpoints multiple times in order to see the application on SigNoz.

.NET application on SigNoz dashboard
.Net Application being monitored on the SigNoz dashboard

You can then visit the traces tab to see traces from your .NET application.

Traces tab of SigNoz dashboard
The traces tab of SigNoz lets you analyze your tracing data with filters and aggregates

The traces tab of SigNoz lets you analyze your tracing data with filters and aggregates

OpenTelemetry .NET instrumentation for Metrics

Below are the few major types of metrics that are used commonly for application monitoring:

  • Counter Instrument non-negative increments, eg: no of bytes received, no of users created.
  • Histogram Instrument arbitrary values that are likely to be statistically meaningful, eg: request duration, size of response payload.
  • Gauge Instrument non-additive values with time, eg: room temperature, no of running tasks.

To illustrate how to collect metrics with OpenTelemetry, let’s create a timed background service.

Step: 1: Create worker app

dotnet new worker -n Org.Worker
cd Org.Worker
Enter fullscreen mode Exit fullscreen mode

Step 2: Modify Worker.cs

using System.Diagnostics;
using System.Diagnostics.Metrics;
namespace Org.Worker;
public class Worker : IHostedService, IDisposable
{
    private readonly ILogger<Worker> _logger;
    private Timer? _timer = null;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service running.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero,
            TimeSpan.FromSeconds(5));   

        return Task.CompletedTask;
    }

    private void DoWork(object? state)
    {
        _logger.LogInformation("Timed Hosted Service is working.");
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Install OpenTelemetry Packages

dotnet add package OpenTelemetry.Extensions.Hosting --prerelease
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --prerelease
Enter fullscreen mode Exit fullscreen mode

Step 4:Configure OpenTelemetry Metrics in Program.cs

using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
...
services.AddOpenTelemetryMetrics(options =>
{
    options
        .SetResourceBuilder(ResourceBuilder.CreateDefault()
            .AddService("Worker")
            .AddEnvironmentVariableDetector()
            .AddTelemetrySdk()
        )
        .AddOtlpExporter(options =>
        {
            options.Endpoint = new Uri("http://localhost:4317");
        });
});
...
Enter fullscreen mode Exit fullscreen mode

Step 5: Create Meter & Counters

...
private static Counter<int> _noOfRunsCounter; 
private static Histogram<float> _timeTakenHistogram;
private static readonly Meter _baseMeter = new("WorkerMeter", "22.05");
...
public Worker(ILogger<Worker> logger)
{
...
    _noOfRunsCounter = _baseMeter.CreateCounter<int>("NoOfRuns");
    _timeTakenHistogram = _baseMeter.CreateHistogram<float>("TimeTaken", "ms");
    _baseMeter.CreateObservableGauge("ThreadCount", () => ThreadPool.ThreadCount);
...
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Update Counters

private void DoWork(object? state)
{
        // Basic Counter metric increment
    _noOfRunsCounter.Add(1);

        // Sleeping for random seconds
    _timer.Change(Timeout.Infinite, Timeout.Infinite);
    var stopwatch = Stopwatch.StartNew();
    var randomValue = new Random().Next(2, 10);
    Thread.Sleep(TimeSpan.FromSeconds(randomValue));
    stopwatch.Stop();

        // Recording Historgram Counter
    _timeTakenHistogram.Record(stopwatch.ElapsedMilliseconds);

    _logger.LogInformation($"Timed Hosted Service sleeping for {randomValue} seconds");
    _timer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Visit SigNoz dashboard http://localhost:3301/dashboard and click on new Dashboard

  • Set Name of the dashboard

  • For Counter: Click on Add Value widget and enter NoOfRuns in PromQL query, and save the widget

  • For Gauge: Now click on time-series widget, enter ThreadCount in PromQL query, and save the widget

  • For Histogram: Click on time-series widget, enter TimeTaken_bucket in PromQL query, and save the widget. Other values which can be viewed TimeTaken_sum and TimeTaken_count

Metrics tab of SigNoz dashboard
Sample Gauge metrics on SigNoz dashboard

OpenTelemetry .NET instrumentation for Logs

Step 1: Create .NET Core Web API

dotnet new webapi -n Org.WebAPI --no-https
cd Org.WebAPI
Enter fullscreen mode Exit fullscreen mode

Step 2: Install OpenTelemetry Packages

dotnet add package OpenTelemetry.Extensions.Hosting --prerelease
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --prerelease
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --prerelease
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure Open Telemetry as Logging Provider

builder.Services.AddOpenTelemetryTracing(budiler =>
{
    budiler
        .AddAspNetCoreInstrumentation(opt =>
        {
            opt.RecordException = true;
        })
        .SetResourceBuilder(ResourceBuilder.CreateDefault()
            .AddService("Org.WebAPI")
            .AddTelemetrySdk()
        )
        .SetErrorStatusOnException(true)
        .AddOtlpExporter(options =>
        {
            options.Endpoint = new Uri("http://localhost:4317"); // Signoz Endpoint
        });
});
Enter fullscreen mode Exit fullscreen mode

Step 4: Let’s create a custom error in Controllers/WeatherForcastController.cs

[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
        throw new Exception("Global Warming");
        ...
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Visit http://localhost:3301/errors to view errors

Exceptions Logging on SigNoz dashboard
Exceptions Logging on SigNoz Dashboard

You can find the code sample used in the tutorial at this GitHub repo.

Conclusion

Using OpenTelemetry .NET client libraries, you can instrument your .NET applications for generating logs, metrics, and traces. You can then use an open-source APM tool like SigNoz to store and visualize the collected telemetry data.

OpenTelemetry is the future for setting up observability for cloud-native apps. It is backed by a huge community and covers a wide variety of technology and frameworks. Using OpenTelemetry, engineering teams can instrument polyglot and distributed applications with peace of mind.

SigNoz is an open-source observability tool that comes with a SaaS-like experience. You can try out SigNoz by visiting its GitHub repo 👇

SigNoz GitHub repo

If you have any questions or need any help in setting things up, join our slack community and ping us in #support channel.

SigNoz Slack community


Further Reading

SigNoz - an open-source alternative to DataDog

Monitor your Spring Boot application with OpenTelemetry

Top comments (2)

Collapse
 
kaylumah profile image
Max Hamulyák

We are also looking into supporting open telemetry in our projects. The thing that is holding us back is that they are prerelease versions.
Have you noticed any differences between versions?

Collapse
 
dchennaraidu profile image
D Chenna Raidu

Using since at-least 6months+, no issues so far