Введение: Почему мониторинг C++ приложений критичен для стабильности?
Современные C++ приложения работают в высоконагруженных средах: игровые серверы, финансовые системы, IoT-устройства и embedded-решения. Без должного мониторинга даже идеально написанный код может привести к катастрофическим последствиям — от утечек памяти до полного падения сервиса в 3 часа ночи. В этой статье мы разберем, как настроить полноценный мониторинг C++ приложений: какие метрики собирать, как организовать логирование и настроить алерты, чтобы спать спокойно.
1. Ключевые метрики C++ приложений
Мониторинг C++ приложений начинается с выбора правильных метрик. Разделим их на три группы:
1.1. Системные метрики (OS-level)
- CPU Usage — загрузка процессора в процентах и время в user/kernel mode.
- Memory Usage — RSS (Resident Set Size), Virtual Memory, количество page faults.
- Disk I/O — операции чтения/записи на диск (особенно важно для баз данных).
- Network I/O — количество отправленных/полученных байт, количество ошибок.
1.2. Метрики приложения (Application-level)
- Request latency — время обработки запросов (p50, p95, p99).
- Throughput — количество обработанных запросов в секунду.
- Error rate — процент ошибок (исключения, таймауты).
- Connection pool — количество активных/ожидающих соединений.
1.3. Метрики C++ runtime
- Memory allocation — количество вызовов new/delete, аллокации в куче.
- Thread count — количество активных потоков, deadlock детекция.
- Object pool utilization — процент занятых объектов в пуле.
Пример экспорта метрик через Prometheus-клиент на C++:
#include <prometheus/exposer.h>
#include <prometheus/registry.h>
#include <prometheus/counter.h>
#include <prometheus/gauge.h>
using namespace prometheus;
int main() {
// Создаем HTTP-сервер для метрик
Exposer exposer{"0.0.0.0:8080"};
auto registry = std::make_shared<Registry>();
// Счетчик запросов
auto& request_counter = BuildCounter()
.Name("http_requests_total")
.Help("Total number of HTTP requests")
.Register(*registry);
// Gauge для текущего количества потоков
auto& thread_gauge = BuildGauge()
.Name("app_thread_count")
.Help("Current number of active threads")
.Register(*registry);
// Регистрируем метрики
exposer.RegisterCollectable(registry);
// Симуляция работы приложения
while (true) {
request_counter.Increment();
thread_gauge.Set(5.0); // Пример значения
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
2. Инструменты сбора метрик: Prometheus и Grafana
Для сбора метрик в C++ экосистеме стандартом де-факто является Prometheus в связке с Grafana. Prometheus — pull-система: ваше приложение отдает метрики по HTTP, а Prometheus сам забирает их с заданным интервалом.
2.1. Настройка экспорта метрик в C++
Популярные библиотеки:
- prometheus-cpp (официальный C++ клиент Prometheus).
- opentelemetry-cpp — для трейсинга и метрик (более современный).
- NanoMsg + custom exporter — для embedded систем.
Пример интеграции с Prometheus-cpp (полный код выше). После запуска проверьте эндпоинт:
curl http://localhost:8080/metrics
# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total 42
# HELP app_thread_count Current number of active threads
# TYPE app_thread_count gauge
app_thread_count 5
2.2. Визуализация в Grafana
Создайте дашборд с панелями:
- CPU и Memory — line chart с агрегацией по времени.
- Latency p99 — heatmap или histogram.
- Error rate — single stat с пороговым значением (красный/зеленый).
3. Логирование и трассировка ошибок
Мониторинг C++ приложений неполон без качественного логирования. Используйте структурированные логи (JSON) для удобного парсинга.
3.1. Библиотеки для логирования
- spdlog — самая быстрая C++ библиотека (header-only, асинхронный режим).
- glog — от Google, удобен для больших проектов.
- fmtlog — сверхбыстрый, на базе fmtlib.
Пример настройки spdlog с выводом в файл и консоль:
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
int main() {
// Консольный логгер с цветами
auto console = spdlog::stdout_color_mt("console");
console->set_level(spdlog::level::info);
// Файловый логгер с ротацией (5 файлов по 10 МБ)
auto file_logger = spdlog::rotating_logger_mt("file_logger",
"/var/log/myapp.log", 1048576 * 10, 5);
file_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
// Примеры логов
file_logger->info("Application started, version {}", APP_VERSION);
file_logger->warn("Memory usage high: {} MB", get_current_memory_mb());
file_logger->error("Failed to connect to database: {}", errno);
}