Мониторинг C# приложений: метрики и алерты продвинутого уровня

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Мониторинг C# приложений: метрики и алерты на продвинутом уровне

В современной разработке на C# (.NET) просто "работающее" приложение перестало быть достаточным критерием качества. Продакшн-системы требуют постоянного наблюдения: нужно знать, сколько памяти потребляет сервис, как быстро обрабатываются запросы, не растёт ли очередь в брокере сообщений. Без системы мониторинга и алертов вы рискуете узнать о проблеме только от пользователей. В этой статье мы разберём продвинутые техники сбора метрик, их визуализации и настройки алертов для C# приложений, используя современные инструменты вроде Prometheus, Grafana и OpenTelemetry.

Зачем нужен продвинутый мониторинг?

Базовый мониторинг (CPU, RAM, диск) не даёт полной картины. Для C# приложений критичны специфические метрики: количество сборок мусора (GC), время блокировок потоков, размер пула подключений к БД. Алерты на эти метрики позволяют реагировать до того, как произойдёт отказ. Продвинутый подход подразумевает три уровня:

  • Infrastructure level — стандартные метрики сервера.
  • Application level — метрики бизнес-логики (задержки, ошибки, частота вызовов).
  • Business level — метрики, связанные с доменом (количество заказов, конверсия).

Мы сосредоточимся на application уровне, который даёт наибольший эффект для C# разработчиков.

Сбор метрик с помощью OpenTelemetry и Prometheus

OpenTelemetry (OTel) — стандарт де-факто для инструментирования .NET приложений. Он позволяет собирать метрики, трейсы и логи единым API. Рассмотрим пример интеграции с Prometheus.

Установите NuGet-пакеты:

dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.AspNetCore

Настройка в Program.cs:

using OpenTelemetry.Metrics;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation()
        .AddRuntimeInstrumentation()
        .AddPrometheusExporter());

var app = builder.Build();

app.MapPrometheusScrapingEndpoint(); // endpoint для Prometheus

app.Run();

Теперь по адресу /metrics ваш сервис будет отдавать метрики в формате Prometheus. Среди них — количество HTTP-запросов, время их обработки, метрики GC и памяти.

Кастомные метрики

Для бизнес-метрик используйте Meter и Counter:

using System.Diagnostics.Metrics;

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

    public OrderMetrics(IMeterFactory meterFactory)
    {
        var meter = meterFactory.Create("MyApp.Orders");
        _ordersCreated = meter.CreateCounter<int>("orders.created.count");
    }

    public void OrderCreated() => _ordersCreated.Add(1);
}

// Регистрация в DI:
builder.Services.AddSingleton<OrderMetrics>();

Эти метрики автоматически попадут в Prometheus и будут доступны для построения дашбордов в Grafana.

Настройка алертов: от простых правил к многоуровневой системе

Сами по себе метрики бесполезны без алертов. В Prometheus алерты настраиваются через Alertmanager. Рассмотрим продвинутый сценарий: алерт на аномальное время ответа API.

Правило в Prometheus (alert.rules.yml)

groups:
  - name: csharp_app_alerts
    rules:
      - alert: HighRequestLatency
        expr: |
          histogram_quantile(0.95, 
            rate(http_server_duration_seconds_bucket[5m])
          ) > 2
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Высокая задержка запросов ({{ $value }}s)"
          description: "P95 latency превышает 2 секунды в течение 2 минут"

Это правило сработает, если 95-й перцентиль времени ответа превышает 2 секунды. Важно использовать for: 2m — это предотвращает ложные срабатывания из-за кратковременных всплесков.

Продвинутые стратегии алертов

  • Multi-window multi-burst: алерт срабатывает только при превышении порога в двух окнах разной длительности (например, 1 минута и 5 минут).
  • Алерты на отсутствие данных: если метрика перестала приходить (например, сервис упал).
  • Алерты на скорость изменения: резкий рост числа ошибок за короткое время.

Пример алерта на отсутствие данных:

- alert: ServiceDown
  expr: absent(up{job="myapp"}) == 1
  for: 1m
  annotations:
    summary: "Сервис myapp не отвечает"

Health Checks и продвинутая диагностика

Встроенные Health Checks в .NET — это не только проверка "жив/не жив". На продвинутом уровне их можно использовать для алертов на состояние зависимостей.

builder.Services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>()
    .AddRedis("localhost:6379")
    .AddUrlGroup(new Uri("https://api.example.com/health"), "External API");

Далее настройте HealthCheckPublisher, который будет отправлять метрики в Prometheus:

public class HealthCheckMetricsPublisher : IHealthCheckPublisher
{
    private readonly Counter<int> _unhealthyCounter;

    public HealthCheckMetricsPublisher(IMeterFactory meterFactory)
    {
        var meter = meterFactory.Create("MyApp.Health");
        _unhealthyCounter = meter.CreateCounter<int>("health.unhealthy.total");
    }

    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        foreach (var entry in report.Entries)
        {
            if (entry.Value.Status != HealthStatus.Healthy)
                _unhealthyCounter.Add(1, new KeyValuePair<string, object?>("check", entry.Key));
        }
        return Task.CompletedTask;
    }
}

// Регистрация:
builder.Services.Configure<HealthCheckPublisherOptions>(opts => opts.Period = TimeSpan.FromSeconds(30));
builder.Services.AddSingleton<IHealthCheckPublisher, HealthCheckMetricsPublisher>();

Блоги

Рекомендаций по книгам