Monitoring C# Applications: Metrics and Alerts in .NET

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

Introduction: Why Monitor C# Applications

Modern C# applications on the .NET platform are complex distributed systems operating under high loads. Without quality monitoring, you risk missing performance degradation, memory leaks, or critical failures. Monitoring allows not only to detect problems but also to predict them, responding to anomalies in a timely manner.

In this article, we will cover how to set up metrics collection, logging, and an alerting system for C# (.NET) applications using modern tools: Prometheus, Grafana, Serilog, and built-in Health Checks. You will get ready-to-use code examples and practical recommendations.



Key Metrics for C# (.NET) Applications

Monitoring begins with defining key indicators. For .NET applications, they can be divided into three categories:

  • Infrastructure metrics — CPU, memory, disk, and network usage.
  • Application metrics — API response time, request count, errors (4xx/5xx), queue sizes.
  • .NET-specific metrics — GC heap size, thread count, garbage collection time, database connection count.


Collecting Metrics via Prometheus and .NET

To export metrics to Prometheus, use the prometheus-net library. Install it via NuGet:

dotnet add package prometheus-net.AspNetCore

Add the middleware in Program.cs:

var builder = WebApplication.CreateBuilder(args);var app = builder.Build();

// Enable Prometheus metricsapp.UseHttpMetrics(); // HTTP metricsapp.UseMetricServer(); // /metrics endpoint

app.MapGet("/", () => "Hello World!");app.Run();

Now standard metrics will be available at the /metrics endpoint: request count, duration, errors. Let's add a custom metric — a counter for endpoint hits:

using Prometheus;

var requestCounter = Metrics.CreateCounter( "myapp_requests_total", "Total requests to the endpoint");

app.MapGet("/api/data", () => { requestCounter.Inc(); return new { Message = "Data loaded" };});


Health Checks: Basic State Verification

The built-in Health Checks mechanism in .NET allows you to quickly assess the application's health. Add a database connection check:

using Microsoft.Extensions.Diagnostics.HealthChecks;

builder.Services.AddHealthChecks() .AddDbContextCheck<AppDbContext>() .AddUrlGroup(new Uri("https://external-api.com"), "External API");

app.MapHealthChecks("/health");

Health Checks return a status of Healthy, Degraded, or Unhealthy — this is an ideal source for alerts.



Logging with Serilog: Structured Logs

Logs are a critical source of data for diagnostics. Serilog allows you to send logs to Elasticsearch, Seq, or simply to a file in a structured format.

Installation:

dotnet add package Serilog.AspNetCoredotnet add package Serilog.Sinks.Seq

Configuration in Program.cs:

Log.Logger = new LoggerConfiguration()    .MinimumLevel.Information()    .WriteTo.Console()    .WriteTo.Seq("http://localhost:5341")    .Enrich.WithProperty("Application", "MyApp")    .CreateLogger();

builder.Host.UseSerilog();

Now all logs will contain contextual information: RequestId, UserId, execution time. Example of logging an error:

try {    // dangerous code} catch (Exception ex) {    Log.Error(ex, "Error processing order {OrderId}", orderId);}

Structured logs are easy to analyze in Grafana or Kibana, build

Blogs

Book Recommendations