1. Вступ
Уявімо, що ви адміністратор сайту, і щодня до вас заходить тисяча користувачів. У логах ви бачите, що все працює, помилок майже немає (хіба що хтось інколи забуває пароль або помиляється з капчею). «Усе чудово!» — думаєте ви.
І раптом хтось пише до підтримки: сайт жахливо гальмує, сторінки відкриваються по 10 секунд. Ви переглядаєте логи — помилок нема! Ура? Ні, бо логи розповідають що сталося (або не сталося), але не показують, наскільки швидко або повільно це відбулося, скільки ресурсів для цього знадобилося і як змінювалася поведінка зі зростанням навантаження.
Ось тут на сцену виходять метрики — вимірювані характеристики роботи застосунку. Це не лише кількість помилок, а й середній час відгуку, обсяг споживаної памʼяті, кількість запитів за секунду та інші показники, за якими можна судити про здоровʼя системи.
Порівняння:
Логи — це "що сталося".
Метрики — це "наскільки добре/погано працює система".
Трасування — це "чому система працює саме так (у деталях)".
Які бувають метрики і що варто збирати?
Основні види метрик:
| Тип метрики | Приклад | Для чого потрібна |
|---|---|---|
| Лічильники (Counters) | Кількість запитів, помилок, збоїв | Тренди, алерти, навантаження |
| Гістограми | Час відповіді, розмір пакета | Розподіл значень, перцентилі |
| Гейджі (Gauge) | Використання памʼяті, CPU | Поточний стан ресурсу |
| Суматори (Sum) | Загальний обсяг даних, байтів | Загальний обсяг операцій за період |
Приклади:
- Середній і 95-й перцентиль часу відповіді на GET-запит.
- Кількість користувачів онлайн просто зараз.
- Використання памʼяті (Private Bytes, Working Set).
- Частота виникнення помилок типу 500/503.
- Запити до БД за хвилину.
Ці показники дають змогу не лише знаходити проблеми, а й запобігати їм — адже підвищене навантаження на сервер або «повзуче» зростання часу відповіді можуть сигналізувати про майбутні збої.
2. Як влаштований збір метрик у .NET та екосистемі OpenTelemetry
Загальна архітектура
У сучасному .NET (починаючи з .NET 6, особливо в .NET 8/9) є стандартна система збирання метрик, заснована на OpenTelemetry.
Ось як це працює:
- Код застосунку викликає методи для збільшення лічильників, реєстрації гейджів, запису гістограм.
- SDK OpenTelemetry Metrics збирає ці метрики (у памʼяті) і періодично надсилає їх.
- Експортер метрик передає їх до обраної системи моніторингу (Prometheus, Application Insights, Grafana Cloud, Datadog тощо).
- Бекенд моніторингу агрегує, зберігає, візуалізує, будує алерти й дашборди.
Схематична блок-схема:
[Твій застосунок]
⬇
[Збір метрик (OpenTelemetry SDK)]
⬇
[Експортер метрик (Prometheus, AI, Datadog, ...)]
⬇
[Система моніторингу/дашборди/алерти]
3. Практика: основи роботи з метриками в C#
Прості внутрішні метрики: System.Diagnostics.Metrics
.NET надає вбудований механізм для метрик — System.Diagnostics.Metrics.
Основні компоненти: Meter, Counter<T>, Histogram<T>, ObservableGauge<T>.
Приклад: лічильник відвідувань сторінки
// Створюємо Meter (зазвичай один на весь застосунок)
using System.Diagnostics.Metrics;
static Meter meter = new Meter("MyCompany.MyApp", "1.0");
// Реєструємо лічильник
static Counter<long> homePageVisits = meter.CreateCounter<long>("HomePageVisits");
// Десь у коді контролера або сервісу...
public void HomePageRequested()
{
homePageVisits.Add(1);
// Далі решта коду обробки сторінки
}
Коментарі:
- Meter — це «фабрика» для метрик з унікальною назвою (простір імен застосунку/компанії).
- CreateCounter<long> — створює лічильник; інкремент через Add(1).
Приклад: вимірювання часу відповіді
static Histogram<double> pageLoadTime = meter.CreateHistogram<double>("PageLoadTimeMs");
// В обробнику запиту:
public void OnRequest()
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// ...тут сам запит...
stopwatch.Stop();
pageLoadTime.Record(stopwatch.Elapsed.TotalMilliseconds);
}
Збираємо гейджі для динамічних значень
Гейдж — показник, який змінюється з часом: кількість підключених користувачів, поточний обсяг памʼяті тощо.
static ObservableGauge<int> onlineUserGauge = meter.CreateObservableGauge(
"OnlineUsers",
() => GetOnlineUserCount());
// Де GetOnlineUserCount — метод, що повертає актуальне значення
static int GetOnlineUserCount()
{
// Тут має бути ваша реальна логіка!
return ActiveUserList.Count;
}
У реальному світі все це працює асинхронно: застосунок публікує значення метрик, а експортер їх відбирає й віддає назовні (наприклад, Prometheus скрейпить endpoint "/metrics").
Додаємо метрики у сучасний ASP.NET Core‑застосунок
Для ASP.NET Core багато чого вже вбудовано. Достатньо додати пакет OpenTelemetry.Instrumentation.AspNetCore — і зʼявляться метрики HTTP‑запитів, часу відповіді, кількості помилок тощо.
Приклад налаштування в Program.cs:
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MyApp"))
.AddAspNetCoreInstrumentation() // метрики HTTP
.AddRuntimeInstrumentation() // метрики середовища виконання .NET CLR
.AddProcessInstrumentation() // CPU/памʼять процесу
.AddMeter("MyCompany.MyApp") // твої метрики
.AddPrometheusExporter(); // експорт у Prometheus
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Тепер ваш застосунок віддаватиме метрики за адресою /metrics, які можна скрейпити через Prometheus або інші системи.
4. Практичні приклади використання метрик
Моніторинг продуктивності в реальних проєктах
Підʼєднуємо метрики, щоб дізнатися:
- Який середній і піковий RPS (requests per second) витримує API?
- Де «вузькі місця»: один endpoint працює 300 мс, інший — 2000 мс?
- Скільки часу минає на виклики БД? (додаємо власні гістограми)
Приклад: контролюємо час відповіді на запити до бази даних
static Histogram<double> dbQueryDuration = meter.CreateHistogram<double>("DbQueryDurationMs");
public async Task<List<Product>> GetProductsAsync()
{
var sw = Stopwatch.StartNew();
var result = await _db.Products.ToListAsync();
sw.Stop();
dbQueryDuration.Record(sw.Elapsed.TotalMilliseconds);
return result;
}
Приклад: рахуємо кількість помилок
static Counter<long> apiErrors = meter.CreateCounter<long>("ApiErrors");
public IActionResult SomeEndpoint()
{
try
{
// якась дія
return Ok();
}
catch (Exception)
{
apiErrors.Add(1);
throw;
}
}
Працюємо з тегами для метрик
Важливо групувати дані за корисними ознаками: endpoint, тип помилки, тип користувача тощо.
homePageVisits.Add(
1,
KeyValuePair.Create<string, object>("UserType", "Admin"));
Або для гістограми:
dbQueryDuration.Record(
sw.Elapsed.TotalMilliseconds,
KeyValuePair.Create<string, object>("QueryType", "GetProducts"));
Завдяки тегам у Grafana можна будувати графіки не лише для всього застосунку, а й за конкретними сегментами.
5. Інтеграція з Prometheus, Application Insights, Datadog, Grafana
Експортери та інтеграція
- Prometheus — популярний open-source моніторинг, де‑факто стандарт для хмар і Kubernetes.
- Application Insights — хмарна інтеграція для Azure.
- Datadog, Grafana Cloud — для професійних інфраструктур.
Усі ці системи можуть збирати метрики з .NET через експортери OpenTelemetry. Документація щодо експортерів OTel.
Prometheus (кроки):
- Додати NuGet‑пакет: OpenTelemetry.Exporter.Prometheus.
- Додати .AddPrometheusExporter() у реєстрацію метрик.
- У Grafana налаштувати datasource на Prometheus і побудувати дашборди.
Корисні посилання:
6. Особливості, підводні камені та типові помилки
Один із частих промахів — надмірна деталізація тегів. Якщо надавати тегам забагато унікальних значень (наприклад, ID користувача/замовлення), кількість часових рядів злетить — це призведе до перевантаження сховища метрик і зростання витрат (так званий cardinality explosion). Залишайте теги достатньо «грубозернистими».
Розробники інколи ігнорують System.Diagnostics.Metrics і готові інструменти, роблять «велосипед» через логи й таймери. У підсумку моніторинг гірше інтегрується й складніше підтримується. Використовуйте стандартні інструменти та автоматичну інструменталізацію.
Ще один промах — метрики збираються, але не експортуються. Налаштування експортера обовʼязкове: додайте, наприклад, .AddPrometheusExporter() і переконайтеся, що endpoint /metrics доступний для скрейпінгу.
І нарешті, плутанина між типами метрик: середній час відгуку рахують через Counter, хоча треба використовувати Histogram — інакше ви не побачите піки та розподіл. Лічильники — для кількості; гістограми — для часу/розмірів/розподілів; гейджі — для поточних станів.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ