Métricas de Prometheus en Rust: monitoreo de rendimiento
Prometheus es el estándar de facto para la recopilación y análisis de métricas en arquitecturas modernas de microservicios. En el ecosistema de Rust existen varias bibliotecas maduras que permiten integrar fácilmente la exportación de métricas en formato Prometheus. En este artículo, analizaremos dos bibliotecas principales: prometheus (cliente oficial) y metrics-exporter-prometheus (parte del framework metrics).
¿Por qué son necesarias las métricas en Rust?
El monitoreo de aplicaciones Rust es fundamental para:
- Seguimiento del rendimiento (latencia, rendimiento)
- Detección de fugas de memoria y problemas de recursos
- Configuración de alertas basadas en valores umbral
- Análisis de tendencias y planificación de capacidad
Biblioteca prometheus (prometheus-rs)
Cliente oficial de Rust para Prometheus. Proporciona un conjunto completo de herramientas para crear y exportar métricas.
Instalación
Agregue a Cargo.toml:
[dependencies]prometheus = { version = "0.13", features = ["process"] }hyper = { version = "0.14", features = ["http1", "server"] }Ejemplo básico: servidor HTTP con métricas
use prometheus::{Counter, HistogramOpts, HistogramVec, IntCounter, Registry, TextEncoder};use std::net::SocketAddr;use hyper::{Body, Request, Response, Server};use hyper::service::{make_service_fn, service_fn};use std::convert::Infallible;use std::sync::Arc;use tokio::sync::Mutex;
#[tokio::main]async fn main() { let registry = Registry::new();
// Creamos un contador de solicitudes let request_counter = IntCounter::new("http_requests_total", "Total HTTP requests") .unwrap(); registry.register(Box::new(request_counter.clone())).unwrap();
// Histograma para el tiempo de respuesta let request_duration = HistogramVec::new( HistogramOpts::new("http_request_duration_seconds", "HTTP request duration"), &["method", "path"] ).unwrap(); registry.register(Box::new(request_duration.clone())).unwrap();
let data = Arc::new(Mutex::new((request_counter, request_duration)));
let make_svc = make_service_fn(move |_conn| { let data = data.clone(); async move { Ok::<_, Infallible>(service_fn(move |req: Request| { let data = data.clone(); async move { let start = std::time::Instant::now(); let (counter, duration) = &*data.lock().await; counter.inc();
// Procesamiento de la solicitud let response = match req.uri().path() { "/metrics" => { let encoder = TextEncoder::new(); let metric_families = registry.gather(); let mut buffer = vec![]; encoder.encode(&metric_families, &mut buffer).unwrap(); Response::new(Body::from(buffer)) } "/" => Response::new(Body::from("Hello, World!")), _ => Response::builder() .status(404) .body(Body::from("Not Found")) .unwrap(), };
let elapsed = start.elapsed().as_secs_f64(); duration .with_label_values(&[req.method().as_str(), req.uri().path()]) .observe(elapsed);
Ok::<_, Infallible>(response) } })) } });
let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); let server = Server::bind(&addr).serve(make_svc); println!("Listening on http://{}", addr); if let Err(e) = server.a También en la biblioteca
Trabajo con YAML en JavaScript (Node.js): análisis, generación y validación
Trabajo con fechas en Swift: Foundation y DateFormatter
Moesif API Monitoring para Node.js
Trabajo con archivos ZIP en TypeScript: guía completa sobre JSZip y adm-zip
Colas de tareas en Java: desde ThreadPoolExecutor hasta Disruptor