Monitoring C# (.NET) Applications with OpenTelemetry and Prometheus

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Monitoring C# (.NET) Applications: A Complete Guide to OpenTelemetry and Prometheus



Modern .NET applications require constant monitoring of performance, errors, and state. Without monitoring, you risk losing control over production. In this article, we will cover how to set up effective monitoring for C# (.NET) applications using the OpenTelemetry (telemetry collection) and Prometheus + Grafana (visualization and alerting) stack.



Why OpenTelemetry?

OpenTelemetry (OTel) is the industry standard for collecting metrics, traces, and logs. For .NET, it provides official SDKs and automatic instrumentation for popular libraries (ASP.NET Core, gRPC, Entity Framework).



Installing and Configuring OpenTelemetry in a C# Project

Add NuGet packages to your project:

dotnet add package OpenTelemetrydotnet add package OpenTelemetry.Extensions.Hostingdotnet add package OpenTelemetry.Instrumentation.AspNetCoredotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore


Basic Configuration in Program.cs

Configure metric collection and export to Prometheus:

using OpenTelemetry.Metrics;using OpenTelemetry.Resources;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry() .ConfigureResource(resource => resource .AddService("MyApp", serviceVersion: "1.0.0")) .WithMetrics(metrics => metrics .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddMeter("Microsoft.AspNetCore.Hosting") .AddMeter("Microsoft.AspNetCore.Server.Kestrel") .AddPrometheusExporter());

var app = builder.Build();

// Endpoint for Prometheus (default /metrics)app.MapPrometheusScrapingEndpoint();

app.Run();


Creating Custom Metrics

You can add your own counters, histograms, and gauges:

using System.Diagnostics.Metrics;

public class OrderMetrics{ private readonly Counter<int> _ordersCreated; private readonly Histogram<double> _orderProcessingTime;

public OrderMetrics(IMeterFactory meterFactory) { var meter = meterFactory.Create("MyApp.Orders"); _ordersCreated = meter.CreateCounter<int>("orders.created", description: "Number of orders created"); _orderProcessingTime = meter.CreateHistogram<double>("orders.processing_time", unit: "ms"); }

public void RecordOrderCreated() => _ordersCreated.Add(1); public void RecordProcessingTime(double ms) => _orderProcessingTime.Record(ms);}


Distributed Tracing

To track call chains, add tracing:

using OpenTelemetry.Trace;

builder.Services.AddOpenTelemetry() .WithTracing(tracing => tracing .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddEntityFrameworkCoreInstrumentation() .AddConsoleExporter()); // For debugging, in production — Jaeger or Zipkin


Logging via OpenTelemetry

Connect the logger to OTel:

using OpenTelemetry.Logs;

builder.Logging.AddOpenTelemetry(logging => logging .AddConsoleExporter() .AddOtlpExporter(options => options.Endpoint = new Uri("http://localhost:4317")));


Configuring Prometheus for Metric Collection

In the prometheus.yml file, specify your endpoint:

scrape_configs:  - job_name: 'dotnet-app'    scrape_interval: 5s    static_configs:      - targets: ['localhost:5000']  # Your application's port


Visualization in Grafana

After connecting Prometheus to Grafana, create a dashboard with key metrics:

  • http_server_duration_ms — server response time
  • http_server_request_count — request count
  • process_cpu_usage — CPU usage
  • process_memory_working_set — memory consumption


Conclusion

Using OpenTelemetry with Prometheus and Grafana provides a complete monitoring solution for .NET applications. This approach allows you to quickly identify bottlenecks, track errors, and ensure stable operation of your services in production.

Recommendations