Métriques Prometheus en Rust : surveillance des performances
Prometheus est la norme de facto pour la collecte et l'analyse de métriques dans les architectures microservices modernes. Dans l'écosystème Rust, il existe plusieurs bibliothèques matures permettant d'intégrer facilement l'export de métriques au format Prometheus. Dans cet article, nous examinerons deux bibliothèques principales : prometheus (le client officiel) et metrics-exporter-prometheus (partie du framework metrics).
Pourquoi des métriques en Rust ?
La surveillance des applications Rust est essentielle pour :
- Suivre les performances (latence, débit)
- Détecter les fuites mémoire et les problèmes de ressources
- Configurer des alertes basées sur des seuils
- Analyser les tendances et planifier la capacité
Bibliothèque prometheus (prometheus-rs)
Le client Rust officiel pour Prometheus. Il fournit un ensemble complet d'outils pour créer et exporter des métriques.
Installation
Ajoutez dans Cargo.toml :
[dependencies]prometheus = { version = "0.13", features = ["process"] }hyper = { version = "0.14", features = ["http1", "server"] }Exemple de base : serveur HTTP avec métriques
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();
// Création d'un compteur de requêtes let request_counter = IntCounter::new("http_requests_total", "Total HTTP requests") .unwrap(); registry.register(Box::new(request_counter.clone())).unwrap();
// Histogramme pour le temps de réponse 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();
// Traitement de la requête 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 Aussi dans la bibliothèque
Travailler avec S3 et les stockages cloud en Java : AWS SDK et MinIO
Travail avec les images en C++ : bibliothèques CImg et STB Image
Jetons JWT en JavaScript (Node.js) : Guide complet
Mise en cache en C# (.NET) : Redis, MemoryCache et autres solutions