Prometheus метрики в Rust: мониторинг производительности
Prometheus — это стандарт де-факто для сбора и анализа метрик в современных микросервисных архитектурах. В экосистеме Rust существует несколько зрелых библиотек, позволяющих легко интегрировать экспорт метрик в формате Prometheus. В этой статье мы рассмотрим две основные библиотеки: prometheus (официальный клиент) и metrics-exporter-prometheus (часть фреймворка metrics).
Зачем нужны метрики в Rust?
Мониторинг Rust-приложений критически важен для:
- Отслеживания производительности (latency, throughput)
- Выявления утечек памяти и проблем с ресурсами
- Настройки алертов на основе пороговых значений
- Анализа трендов и планирования ёмкости
Библиотека prometheus (prometheus-rs)
Официальный Rust-клиент для Prometheus. Предоставляет полный набор инструментов для создания и экспорта метрик.
Установка
Добавьте в Cargo.toml:
[dependencies]
prometheus = { version = "0.13", features = ["process"] }
hyper = { version = "0.14", features = ["http1", "server"] }
Базовый пример: HTTP-сервер с метриками
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();
// Создаём счётчик запросов
let request_counter = IntCounter::new("http_requests_total", "Total HTTP requests")
.unwrap();
registry.register(Box::new(request_counter.clone())).unwrap();
// Гистограмма для времени ответа
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();
// Обработка запроса
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.await {
eprintln!("Server error: {}", e);
}
}
Библиотека metrics-exporter-prometheus
Часть экосистемы metrics — более абстрактного и модульного подхода к метрикам. Позволяет легко переключаться между бэкендами (Prometheus, StatsD, stdout).
Установка
[dependencies]
metrics = "0.21"
metrics-exporter-prometheus = "0.12"
Пример использования
use metrics::{counter, histogram, describe_counter, describe_histogram};
use metrics_exporter_prometheus::PrometheusBuilder;
use std::net::SocketAddr;
use std::time::Instant;
fn main() {
// Настройка экспортёра
let builder = PrometheusBuilder::new();
let handle = builder
.listen_address(SocketAddr::from(([127, 0, 0, 1], 9000)))
.install()
.expect("Failed to install Prometheus exporter");
// Описание метрик (опционально)
describe_counter!("http_requests_total", "Total number of HTTP requests");
describe_histogram!("http_request_duration_seconds", "HTTP request duration in seconds");
// Эмуляция работы
for i in 0..100 {
let start = Instant::now();
// Симуляция обработки запроса
std::thread::sleep(std::time::Duration::from_millis(10));