Monitoreo de aplicaciones Rust: métricas y alertas de la A a la Z

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

Monitoreo de aplicaciones Rust: métricas y alertas de la A a la Z

\n\n

Cuando tu aplicación Rust llega a producción, el código deja de ser solo código. Se convierte en un servicio del que dependen usuarios y negocios. Sin monitoreo, vuelas a ciegas: las fallas se detectan por quejas y el rendimiento se evalúa "a ojo". En este artículo, analizaremos cómo construir un sistema de monitoreo completo para Rust, desde la recopilación de métricas básicas hasta la configuración de alertas en Prometheus y la visualización en Grafana.

\n\n

1. Por qué el monitoreo es importante para proyectos Rust

\n

Rust es conocido por su rendimiento y seguridad de memoria, pero eso no elimina la necesidad de supervisar la aplicación. Problemas típicos en producción:

\n
    \n
  • Fugas de memoria (por ejemplo, a través de Arc o referencias cíclicas).
  • \n
  • Bloqueos en código async (deadlocks o starvation en tokio).
  • \n
  • Pánicos inesperados (incluso con catch_unwind).
  • \n
  • Degradación del rendimiento debido a algoritmos no óptimos.
  • \n
\n

El monitoreo responde a las preguntas: "¿Qué está pasando ahora?", "¿Por qué sucedió?" y "¿Cómo prevenirlo?".

\n\n

2. Recopilación de métricas: biblioteca metrics y exportación a Prometheus

\n

El stack estándar para Rust es el crate metrics (o prometheus). Usamos metrics porque abstrae la exportación y facilita cambiar de backend.

\n\n

2.1. Instalación y configuración básica

\n

Agrega las dependencias en Cargo.toml:

\n
[dependencies]\nmetrics = "0.21"\nmetrics-exporter-prometheus = "0.12"\ntokio = { version = "1", features = ["full"] }
\n\n

Creamos un servidor HTTP simple para el endpoint /metrics:

\n
use metrics_exporter_prometheus::PrometheusBuilder;\nuse std::net::SocketAddr;\nuse tokio::net::TcpListener;\n\n#[tokio::main]\nasync fn main() {\n    // Inicializamos el exportador Prometheus\n    let (recorder, exporter) = PrometheusBuilder::new()\n        .build()\n        .expect("No se pudo crear el exportador Prometheus");\n\n    metrics::set_boxed_recorder(Box::new(recorder))\n        .expect("No se pudo establecer el grabador global");\n\n    // Iniciamos el servidor de métricas\n    let addr: SocketAddr = "0.0.0.0:9090".parse().unwrap();\n    let listener = TcpListener::bind(addr).await.unwrap();\n    println!("Métricas disponibles en http://{}", addr);\n\n    loop {\n        let (mut stream, _) = listener.accept().await.unwrap();\n        let body = exporter.encode().unwrap();\n        let response = format!(\n            "HTTP/1.1 200 OK\\r\\nContent-Type: text/plain\\r\\nContent-Length: {}\\r\\n\\r\\n{}",\n            body.len(),\n            body\n        );\n        tokio::io::AsyncWriteExt::write_all(&mut stream, response.as_bytes())\n            .await\n            .unwrap();\n    }\n}
\n\n

2.2. Registro de métricas personalizadas

\n

Agregamos un contador de solicitudes y un histograma de tiempo de respuesta:

\n
use metrics::{counter, histogram, increment_counter};\nuse std::time::Instant;\n\nasync fn handle_request() {\n    let start = Instant::now();\n\n    // Tu lógica de negocio\n    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;\n\n    // Registramos las métricas\n    increment_counter!("http_requests_total", "method" => "GET");\n    histogram!("http_request_duration_seconds", start.elapsed().as_secs_f64(), "method" => "GET");\n}
\n

Ahora en /metrics verás:

\n
# HELP http_requests_total Total HTTP requests\n# TYPE http_requests_total counter\nhttp_requests_total{method="GET"} 1\n# HELP http_request_duration_seconds HTTP request duration\n# TYPE http_request_duration_seconds histogram\nhttp_request_duration_seconds_bucket{method="GET",le="0.005"} 0\nhttp_request_duration_seconds_bucket{method="GET",le="0.01"} 0\nhttp_request_duration_seconds_bucket{method="GET",le="0.025"} 0\n                

Blogs

Book Recommendations