Monitoreo de aplicaciones Rust: métricas y alertas a nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Por qué el monitoreo de aplicaciones Rust es un desafío y una oportunidad



Rust es conocido por su rendimiento y seguridad de memoria. Sin embargo, cuando tu aplicación opera al límite del hardware (por ejemplo, un servidor WebSocket de alta carga o un analizador de datos), las métricas estándar de CPU y RAM a menudo resultan insuficientes. A nivel avanzado, el monitoreo de aplicaciones Rust no solo requiere recopilar datos, sino crear un sistema de alertas preciso que prediga una falla antes de que ocurra.



En este artículo, veremos cómo construir un sistema de monitoreo listo para producción para Rust: desde métricas personalizadas usando el crate prometheus hasta la configuración de alertas a través de Alertmanager y Grafana.



1. Métricas avanzadas: no solo solicitudes HTTP



El monitoreo básico (número de solicitudes, latencias) es el mínimo. A nivel avanzado, recopilamos métricas que reflejan el estado interno de la aplicación: tamaño de colas, número de tareas activas en Tokio, estado del pool de conexiones.



1.1. Métricas personalizadas con tipo Histogram y Gauge



Usamos el crate prometheus. Veamos un ejemplo de recopilación de métricas para un pool de conexiones a la base de datos:



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 actual de conexiones activas en el pool" ).unwrap();

static ref DB_QUERY_DURATION: HistogramVec = register_histogram_vec!( HistogramOpts::new("db_query_duration_seconds", "Tiempo de ejecución de consulta a la BD"), &["query_type", "status"] ).unwrap();}

// Uso en el códigofn execute_query(query_type: &str) -> Result<(), String> { DB_CONNECTION_POOL.inc(); let start = std::time::Instant::now(); // ... ejecución de la 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: Usa HistogramVec para categorizar las consultas por tipo (SELECT, INSERT) y estado (success, error). Esto permitirá crear mapas de calor en Grafana.



1.2. Métricas desde el interior del runtime de Tokio



Para aplicaciones asíncronas, es crítico conocer la carga del planificador. 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(); // Enviamos estos valores a Prometheus a través de Gauge println!("Tareas activas: {}, Hilos bloqueantes: {}", num_alive_tasks, blocking_threads); }}


Estas métricas ayudan a detectar fugas de tareas (cuando num_alive_tasks crece constantemente) o el uso excesivo de block_in_place.



2. Arquitectura de recopilación de métricas: Push vs Pull



En el ecosistema Rust, se usa más el modelo Pull (recolector de Prometheus), pero para procesos de corta duración (utilidades CLI, analizadores) es conveniente el enfoque Push a través de Pushgateway.



2.1. Modelo Pull: Endpoint HTTP



La forma estándar es ejecutar un servidor HTTP separado en el puerto 9090 (u otro) dentro de tu aplicación:



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