Prometheus метрики в Rust: библиотека prometheus и metrics

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Prometheus метрики в Rust: мониторинг производительности и отказоустойчивости

В современной разработке бэкенд-приложений на Rust мониторинг стал неотъемлемой частью production-инфраструктуры. Prometheus — стандарт де-факто для сбора и хранения метрик, а его интеграция с Rust позволяет отслеживать производительность, загрузку CPU, количество запросов, ошибок и многое другое. В этой статье мы рассмотрим две основные библиотеки: prometheus (официальный клиент) и metrics + metrics-exporter-prometheus (более абстрактный подход).

Зачем нужны метрики в Rust?

Метрики позволяют:

  • Отслеживать состояние сервиса в реальном времени
  • Обнаруживать узкие места (latency, ошибки)
  • Строить дашборды в Grafana
  • Настраивать алерты (например, при падении QPS или росте ошибок)

Установка и настройка библиотеки prometheus

Добавьте в Cargo.toml:

[dependencies]
prometheus = { version = "0.13", features = ["process"] }
actix-web = "4"  # для примера с веб-сервером
tokio = { version = "1", features = ["full"] }

Библиотека prometheus предоставляет три основных типа метрик: Counter, Gauge, Histogram.

Пример: создание и регистрация метрик

use prometheus::{Counter, Gauge, Histogram, HistogramOpts, Opts, Registry};

fn main() {
    // Создаём реестр метрик
    let registry = Registry::new();

    // Counter — счётчик запросов
    let request_counter = Counter::with_opts(
        Opts::new("http_requests_total", "Total HTTP requests")
            .const_label("service", "my_app")
    ).unwrap();
    registry.register(Box::new(request_counter.clone())).unwrap();

    // Gauge — текущее количество активных соединений
    let active_connections = Gauge::with_opts(
        Opts::new("active_connections", "Number of active connections")
    ).unwrap();
    registry.register(Box::new(active_connections.clone())).unwrap();

    // Histogram — распределение времени ответа
    let request_duration = Histogram::with_opts(
        HistogramOpts::new("http_request_duration_seconds", "Request duration in seconds")
            .buckets(vec![0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0])
    ).unwrap();
    registry.register(Box::new(request_duration.clone())).unwrap();

    // Имитация использования
    request_counter.inc();
    active_connections.set(42.0);
    request_duration.observe(0.123);
}

Экспорт метрик через HTTP (actix-web)

Чтобы Prometheus мог собирать метрики, нужно отдать их в формате /metrics:

use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use prometheus::{Encoder, TextEncoder, Registry};
use std::sync::Arc;

async fn metrics_handler(registry: web::Data<Arc<Registry>>) -> impl Responder {
    let encoder = TextEncoder::new();
    let mut buffer = Vec::new();
    encoder.encode(®istry.gather(), &mut buffer).unwrap();
    HttpResponse::Ok()
        .content_type("text/plain; charset=utf-8")
        .body(buffer)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let registry = Arc::new(Registry::new());
    // ... регистрируем метрики как выше ...

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(registry.clone()))
            .route("/metrics", web::get().to(metrics_handler))
    })
    .bind("127.0.0.1:9090")?
    .run()
    .await
}

Библиотека metrics — высокоуровневый подход

Альтернатива — крейт metrics с экспортёром metrics-exporter-prometheus. Он предоставляет макросы для быстрого создания метрик:

[dependencies]
metrics = "0.21"
metrics-exporter-prometheus = "0.12"
use metrics::{counter, gauge, histogram};
use metrics_exporter_prometheus::PrometheusBuilder;

fn main() {
    // Устанавливаем экспортёр Prometheus
    let (recorder, exporter) = PrometheusBuilder::new()
        .build()
        .expect("failed to build prometheus exporter");
    metrics::set_boxed_recorder(Box::new(recorder)).unwrap();

    // Используем макросы
    counter!("http_requests_total", 1, "service" => "my_app");
    gauge!("active_connections", 42.0);
    histogram!("http_request_duration_seconds", 0.123);

    // Запускаем HTTP сервер для экспорта (отдельный поток)                    

Рекомендаций