Назад к блогу

Monitoring API

17 Янв, 2026

## Конфигурационная система

### Основной класс конфигурации

Класс `MonitoringConfig` определяет все настраиваемые параметры системы мониторинга:

«`rust
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MonitoringConfig {
pub enabled: bool, // Включение/выключение системы
pub prometheus_enabled: bool, // Экспорт метрик в Prometheus
pub prometheus_port: u16, // Порт для Prometheus (9090 по умолчанию)
pub alerting_enabled: bool, // Включение системы оповещений
pub metrics_interval_sec: u64, // Интервал сбора метрик в секундах
pub retention_days: u32, // Дни хранения исторических данных
pub max_alerts: usize, // Максимальное количество хранимых оповещений
}
«`

### Значения по умолчанию

Система предоставляет разумные значения по умолчанию для всех параметров:

«`rust
impl Default for MonitoringConfig {
fn default() -> Self {
Self {
enabled: true,
prometheus_enabled: true,
prometheus_port: 9090,
alerting_enabled: true,
metrics_interval_sec: 60,
retention_days: 30,
max_alerts: 1000,
}
}
}
«`

## UnifiedMonitor — ядро системы

### Инициализация центрального монитора

Класс `UnifiedMonitor` является центральным компонентом системы:

«`rust
pub struct UnifiedMonitor {
monitors: Arc>>>,
health_checks: Arc>>>,
alerts: Arc>>,
config: MonitoringConfig,
health_history: Arc>>,
}

impl UnifiedMonitor {
pub fn new(config: MonitoringConfig) -> Self {
Self {
monitors: Arc::new(RwLock::new(HashMap::new())),
health_checks: Arc::new(RwLock::new(HashMap::new())),
alerts: Arc::new(RwLock::new(VecDeque::with_capacity(config.max_alerts))),
config,
health_history: Arc::new(RwLock::new(VecDeque::with_capacity(100))),
}
}
}
«`

### Основные интерфейсы

#### Интерфейс Monitor

Все мониторы должны реализовывать следующий интерфейс:

«`rust
#[async_trait::async_trait]
pub trait Monitor: Send + Sync {
fn name(&self) -> &’static str;
async fn collect_metrics(&self) -> MonitorMetrics;
async fn health_check(&self) -> bool;
async fn reset_metrics(&self);
}
«`

#### Интерфейс HealthCheckable

Компоненты проверки здоровья реализуют этот интерфейс:

«`rust
#[async_trait]
pub trait HealthCheckable: Send + Sync {
async fn health_check(&self) -> HealthStatus;
fn component_name(&self) -> &’static str;
fn component_type(&self) -> ComponentType;
}
«`

## Монитор сервера (ServerMonitor)

### Структура метрик сервера

Класс `ServerMonitor` отслеживает метрики, связанные с работой сервера:

«`rust
#[derive(Debug, Clone)]
pub struct ServerMetrics {
pub active_sessions: u64, // Активные пользовательские сессии
pub total_connections: u64, // Общее количество соединений
pub failed_connections: u64, // Неудачные попытки подключения
pub heartbeat_timeouts: u64, // Пропущенные heartbeat’ы
pub avg_response_time: f64, // Среднее время ответа
}
«`

### Инициализация и управление сессиями

«`rust
impl ServerMonitor {
pub fn new() -> Self {
Self {
metrics: Arc::new(RwLock::new(ServerMetrics {
active_sessions: 0,
total_connections: 0,
failed_connections: 0,
heartbeat_timeouts: 0,
avg_response_time: 0.0,
})),
unified_monitor: None,
}
}

pub async fn record_session_connected(&self) {
let mut metrics = self.metrics.write().await;
metrics.active_sessions += 1;
metrics.total_connections += 1;
}

pub async fn record_session_disconnected(&self) {
let mut metrics = self.metrics.write().await;
metrics.active_sessions = metrics.active_sessions.saturating_sub(1);
}
}
«`

## Проверки здоровья (Health Checks)

### DatabaseHealthCheck

Проверка работоспособности базы данных с механизмом повторных попыток:

«`rust
impl DatabaseHealthCheck {
async fn execute_health_query_with_retry(&self) -> Result<(bool, u128), String> {
const MAX_RETRIES: u32 = 3;
const INITIAL_DELAY_MS: u64 = 100;

let mut last_error = None;

for attempt in 0..MAX_RETRIES {
match self.execute_single_health_query().await {
Ok(result) => return Ok(result),
Err(e) => {
last_error = Some(e);

if attempt < MAX_RETRIES - 1 { let delay_ms = INITIAL_DELAY_MS * 2u64.pow(attempt); tokio::time::sleep(Duration::from_millis(delay_ms)).await; } } } } Err(last_error.unwrap_or_else(|| "All retry attempts failed".to_string())) } } ``` ### NetworkHealthCheck Проверка сетевой доступности внешних ресурсов: ```rust impl NetworkHealthCheck { async fn check_external_connectivity_async(&self) -> Result, String> {
let mut results = Vec::new();
let targets = vec![
(«google.com», 80),
(«cloudflare.com», 80),
(«github.com», 80),
];

let mut futures = Vec::new();

for (host, port) in targets {
let host = host.to_string();
futures.push(async move {
match self.check_port_async(&host, port, 3).await {
Ok(duration) => Ok((format!(«{}:{}», host, port), duration)),
Err(e) => Err(format!(«{}:{} — {}», host, port, e)),
}
});
}

let check_results = futures::future::join_all(futures).await;
// Обработка результатов…
}
}
«`

### MemoryHealthCheck с кэшированием

Проверка использования памяти с интеллектуальным кэшированием:

«`rust
pub struct MemoryHealthCheck {
cache: SimpleCache,
system_info: Arc,
}

impl MemoryHealthCheck {
pub fn new() -> Self {
Self {
cache: SimpleCache::new(Duration::from_secs(10)),
system_info: Arc::new(RealSystemInfo),
}
}

async fn get_memory_info_cached(&self) -> serde_json::Value {
self.cache.get_or_compute(|| async {
match self.system_info.get_memory_info().await {
Ok(mem_info) => {
let total_mb = mem_info.total / 1024;
let available_mb = mem_info.avail / 1024;
let used_mb = total_mb.saturating_sub(available_mb);
let usage_percent = (used_mb as f64 / total_mb as f64) * 100.0;

serde_json::json!({
«total_mb»: total_mb,
«used_mb»: used_mb,
«available_mb»: available_mb,
«usage_percent»: usage_percent,
«is_healthy»: usage_percent < 90.0, "status": if usage_percent < 80.0 { "Normal" } else if usage_percent < 90.0 { "High" } else { "Critical" } }) }, Err(e) => serde_json::json!({
«error»: format!(«Cannot read memory info: {}», e)
})
}
}).await
}
}
«`

## Система кэширования

### Класс MetricsCache

Общий кэш для хранения метрик с поддержкой TTL (Time-To-Live):

«`rust
pub struct MetricsCache {
cache: Arc>>,
ttl: Duration,
}

impl MetricsCache {
pub async fn get_or_compute(&self, key: &str, computer: F) -> serde_json::Value
where
F: FnOnce() -> Fut,
Fut: Future,
{
let now = Instant::now();
let mut cache = self.cache.write().await;

if let Some((timestamp, value)) = cache.get(key) {
if now.duration_since(*timestamp) < self.ttl { return value.clone(); } } let value = computer().await; cache.insert(key.to_string(), (now, value.clone())); value } } ``` ## MonitorRegistry - реестр мониторов ### Инициализация системы Класс `MonitorRegistry` отвечает за регистрацию всех компонентов мониторинга: ```rust impl MonitorRegistry { pub async fn new() -> Self {
info!(«🚀 Initializing comprehensive monitoring system…»);

let config = MonitoringConfig::default();
let unified_monitor = Arc::new(UnifiedMonitor::new(config));

// Регистрация серверного монитора
let server_monitor = ServerMonitor::new();
unified_monitor.register_monitor(Arc::new(server_monitor.clone())).await;

// Регистрация системных проверок здоровья
unified_monitor.register_health_check(Arc::new(DatabaseHealthCheck::new())).await;
unified_monitor.register_health_check(Arc::new(NetworkHealthCheck::new())).await;
unified_monitor.register_health_check(Arc::new(MemoryHealthCheck::new())).await;
unified_monitor.register_health_check(Arc::new(CpuHealthCheck::new())).await;
unified_monitor.register_health_check(Arc::new(DiskHealthCheck::new())).await;
unified_monitor.register_health_check(Arc::new(ApiHealthCheck::new())).await;

// Создание вспомогательных компонентов
let start_time = Instant::now();
let health_runner = HealthCheckRunner::new(Arc::clone(&unified_monitor));
let metrics_reporter = MetricsReporter::new(Arc::clone(&unified_monitor), start_time);

Self {
unified_monitor,
server_monitor: Arc::new(server_monitor),
health_runner,
metrics_reporter,
start_time,
}
}
}
«`

### Запуск фонового мониторинга

«`rust
pub async fn start_background_monitoring(self: Arc) -> BackgroundMonitorHandle {
let registry = Arc::clone(&self);
tokio::spawn(async move {
// Первая проверка через 30 секунд после запуска
tokio::time::sleep(Duration::from_secs(30)).await;

let mut interval = interval(Duration::from_secs(60));
let mut error_count = 0;
const MAX_CONSECUTIVE_ERRORS: u32 = 5;

loop {
interval.tick().await;
let report = registry.health_runner.get_detailed_report().await;

if !report.overall_health {
error_count += 1;
if error_count >= MAX_CONSECUTIVE_ERRORS {
error_count = 0;
tokio::time::sleep(Duration::from_secs(300)).await;
continue;
}
} else {
error_count = 0;
}

// Детальный отчет каждые 5 минут
if registry.start_time.elapsed().as_secs() % 300 < 60 { registry.metrics_reporter.print_comprehensive_report().await; } } }); BackgroundMonitorHandle::new() } ``` ## Система логирования ### Настройка логирования Функция `init_logging` настраивает систему логирования с кастомным форматом: ```rust pub fn init_logging() { let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); tracing_subscriber::fmt() .with_env_filter(filter) .with_timer(CustomTime) // UTC время с миллисекундами .with_file(true) // Отображение имени файла .with_line_number(true) // Отображение номера строки .init(); } ``` ### Макросы для мониторинга Специальные макросы добавляют контекстную информацию к логам: ```rust #[macro_export] macro_rules! monitor_info { ($msg:literal $(, $key:ident = $value:expr)*) => {
tracing::info!(
monitor_component = module_path!(), // Автоматическое имя компонента
$($key = $value,)*
$msg
)
};
}
«`

## Типы данных и структуры

### HealthStatus

Структура для представления статуса здоровья компонента:

«`rust
#[derive(Debug, Serialize, Clone)]
pub struct HealthStatus {
pub is_healthy: bool, // Бинарный статус здоровья
pub message: String, // Человекочитаемое сообщение
pub details: Option, // Детальная информация
pub timestamp: u64, // Временная метка
}
«`

### SystemHealthReport

Комплексный отчет о состоянии системы:

«`rust
#[derive(Debug, Serialize, Clone)]
pub struct SystemHealthReport {
pub overall_health: bool, // Общий статус системы
pub components: HashMap, // Статусы компонентов
pub critical_components: Vec, // Критически важные компоненты
pub warnings: Vec, // Предупреждения
pub timestamp: u64, // Временная метка отчета
}
«`

### Alert и AlertLevel

Система оповещений с уровнями серьезности:

«`rust
#[derive(Debug, Serialize, Clone, PartialEq)]
pub enum AlertLevel {
Info, // Информационные сообщения
Warning, // Предупреждения
Error, // Ошибки
Critical, // Критические события
}

#[derive(Debug, Serialize, Clone)]
pub struct Alert {
pub level: AlertLevel, // Уровень серьезности
pub source: String, // Источник оповещения
pub message: String, // Текст сообщения
pub timestamp: u64, // Временная метка
pub metadata: HashMap, // Дополнительные метаданные
}
«`

## Работа с системной информацией

### Интерфейс SystemInfoProvider

Абстрактный интерфейс для получения системной информации:

«`rust
#[async_trait]
pub trait SystemInfoProvider: Send + Sync {
async fn get_memory_info(&self) -> Result;
async fn get_load_avg(&self) -> Result;
async fn get_disk_info(&self) -> Result;
}
«`

### Реализация RealSystemInfo

Реальная реализация, использующая системные вызовы:

«`rust
pub struct RealSystemInfo;

#[async_trait]
impl SystemInfoProvider for RealSystemInfo {
async fn get_memory_info(&self) -> Result {
tokio::task::spawn_blocking(|| {
sys_info::mem_info()
.map(|info| MemoryInfo {
total: info.total,
free: info.free,
avail: info.avail,
})
.map_err(|e| e.to_string())
})
.await
.map_err(|e| e.to_string())?
}
}
«`

## Экспорт метрик

### Поддержка Prometheus

Система поддерживает экспорт метрик в формате Prometheus:

«`rust
pub async fn get_prometheus_metrics(&self) -> String {
if !self.config.prometheus_enabled {
return String::new();
}

let all_metrics = self.collect_all_metrics().await;
let mut prometheus_output = String::new();

for (monitor_name, metrics) in all_metrics {
for (metric_name, metric_value) in metrics.metrics {
let metric_line = match metric_value {
MetricValue::Counter(value) => {
format!(«{}_{}{{monitor=\»{}\»}} {}\n»,
monitor_name, metric_name, monitor_name, value)
}
MetricValue::Gauge(value) => {
format!(«{}_{}{{monitor=\»{}\»}} {}\n»,
monitor_name, metric_name, monitor_name, value)
}
_ => continue,
};
prometheus_output.push_str(&metric_line);
}
}

prometheus_output
}
«`

## Практическое использование

### Добавление нового монитора

Для добавления нового монитора необходимо:

1. Реализовать трейт `Monitor` или `HealthCheckable`
2. Зарегистрировать в `MonitorRegistry::new()`
3. Настроить параметры сбора метрик

**Пример кастомного монитора:**

«`rust
pub struct CustomMonitor {
metrics: Arc>,
}

#[async_trait::async_trait]
impl Monitor for CustomMonitor {
fn name(&self) -> &’static str {
«custom_monitor»
}

async fn collect_metrics(&self) -> MonitorMetrics {
let metrics = self.metrics.read().await;
let mut metric_map = HashMap::new();

metric_map.insert(«custom_counter».to_string(),
MetricValue::Counter(metrics.counter));

MonitorMetrics {
name: self.name().to_string(),
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs(),
metrics: metric_map,
health: self.health_check().await,
}
}

async fn health_check(&self) -> bool {
true
}

async fn reset_metrics(&self) {
let mut metrics = self.metrics.write().await;
metrics.counter = 0;
}
}
«`

### Настройка конфигурации

Конфигурация может быть загружена из файла или установлена программно:

«`rust
let config = MonitoringConfig {
enabled: true,
prometheus_enabled: true,
prometheus_port: 9090,
alerting_enabled: true,
metrics_interval_sec: 30, // Уменьшенный интервал
retention_days: 14,
max_alerts: 500,
};

let monitor = UnifiedMonitor::new(config);
«`

## Оптимизация производительности

### Кэширование результатов

Система использует многоуровневое кэширование для оптимизации производительности:

«`rust
impl MemoryHealthCheck {
async fn get_memory_info_cached(&self) -> serde_json::Value {
self.cache.get_or_compute(|| async {
// Тяжелая операция получения информации о памяти
self.system_info.get_memory_info().await
}).await
}
}
«`

### Асинхронные операции

Все операции сбора метрик выполняются асинхронно:

«`rust
pub async fn collect_all_metrics(&self) -> HashMap {
let monitors = self.monitors.read().await;
let mut futures = Vec::new();

for (name, monitor) in monitors.iter() {
let name_clone = name.clone();
let monitor_clone = monitor.clone();
futures.push(async move {
let metrics = monitor_clone.collect_metrics().await;
(name_clone, metrics)
});
}

futures::future::join_all(futures).await.into_iter().collect()
}
«`

## Обработка ошибок

### Механизмы повторных попыток

Система реализует паттерн повторных попыток с экспоненциальным откладыванием:

«`rust
async fn execute_health_query_with_retry(&self) -> Result<(bool, u128), String> {
const MAX_RETRIES: u32 = 3;
const INITIAL_DELAY_MS: u64 = 100;

for attempt in 0..MAX_RETRIES {
match self.execute_single_health_query().await {
Ok(result) => return Ok(result),
Err(e) => {
if attempt < MAX_RETRIES - 1 { let delay_ms = INITIAL_DELAY_MS * 2u64.pow(attempt); tokio::time::sleep(Duration::from_millis(delay_ms)).await; } } } } Err("All retry attempts failed".to_string()) } ``` ## Заключение Данная система мониторинга предоставляет комплексное решение для наблюдения за состоянием приложений. Модульная архитектура, поддержка асинхронных операций и расширяемость делают её подходящей для использования в проектах различного масштаба. Система готова к интеграции с внешними инструментами мониторинга и может быть расширена для решения специфических задач.