Monitoramento de aplicações Rust: métricas e alertas em nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que monitorar aplicações Rust é um desafio e uma oportunidade



Rust é conhecido por seu desempenho e segurança de memória. No entanto, quando sua aplicação opera no limite do hardware (por exemplo, um servidor WebSocket de alta carga ou um analisador de dados), as métricas padrão de CPU e RAM geralmente são insuficientes. Em nível avançado, o monitoramento de aplicações Rust exige não apenas a coleta de dados, mas a criação de um sistema preciso de alertas que preveja uma falha antes que ela ocorra.



Neste artigo, veremos como construir um sistema de monitoramento pronto para produção para Rust: desde métricas personalizadas usando o crate prometheus até a configuração de alertas via Alertmanager e Grafana.



1. Métricas avançadas: não apenas requisições HTTP



O monitoramento básico (número de requisições, latências) é o mínimo. Em nível avançado, coletamos métricas que refletem o estado interno da aplicação: tamanho das filas, número de tarefas ativas no Tokio, estado do pool de conexões.



1.1. Métricas personalizadas com os tipos Histogram e Gauge



Usamos o crate prometheus. Veja um exemplo de coleta de métricas para um pool de conexões de banco de dados:



use prometheus::{HistogramOpts, HistogramVec, Gauge, register_histogram_vec, register_gauge};use lazy_static::lazy_static;

lazy_static! { static ref DB_CONNECTION_POOL: Gauge = register_gauge!( "db_connection_pool_size", "Número atual de conexões ativas no pool" ).unwrap();

static ref DB_QUERY_DURATION: HistogramVec = register_histogram_vec!( HistogramOpts::new("db_query_duration_seconds", "Tempo de execução da consulta ao BD"), &["query_type", "status"] ).unwrap();}

// Uso no códigofn execute_query(query_type: &str) -> Result<(), String> { DB_CONNECTION_POOL.inc(); let start = std::time::Instant::now(); // ... execução da consulta ... let duration = start.elapsed().as_secs_f64(); DB_QUERY_DURATION.with_label_values(&[query_type, "success"]).observe(duration); DB_CONNECTION_POOL.dec(); Ok(())}


Importante: Use HistogramVec para categorizar consultas por tipo (SELECT, INSERT) e status (success, error). Isso permitirá criar mapas de calor no Grafana.



1.2. Métricas internas do Tokio runtime



Para aplicações assíncronas, é crucial conhecer a carga do escalonador. Usamos tokio-metrics:



use tokio_metrics::RuntimeMetrics;use std::sync::Arc;

async fn monitor_runtime(metrics: Arc<RuntimeMetrics>) { loop { tokio::time::sleep(std::time::Duration::from_secs(5)).await; let num_alive_tasks = metrics.num_alive_tasks(); let blocking_threads = metrics.num_blocking_threads(); // Envia esses valores para o Prometheus via Gauge println!("Tarefas ativas: {}, Threads bloqueantes: {}", num_alive_tasks, blocking_threads); }}


Essas métricas ajudam a identificar vazamentos de tarefas (quando num_alive_tasks cresce constantemente) ou uso excessivo de block_in_place.



2. Arquitetura de coleta de métricas: Push vs Pull



No ecossistema Rust, o modelo Pull (Prometheus scraper) é mais comum, mas para processos de curta duração (utilitários CLI, analisadores), a abordagem Push via Pushgateway é conveniente.



2.1. Modelo Pull: Endpoint HTTP



A maneira padrão é iniciar um servidor HTTP separado na porta 9090 (ou outra) dentro da sua aplicação:



use warp::Filter;use prometheus::{Encoder, TextEncoder};

async fn metrics_handler() -> Result<impl warp::Reply, warp::Rejection> { let metric_families = prometheus::gather(); let mut buffer = Vec::new(); let encoder = TextEncoder::new(); encoder.encode(&metric_families, &mut buffer).unwrap(); Ok(warp::reply::with_header(bu

Blogs

Book Recommendations