Мониторинг приложений Rust: Обзор ключевых инструментов и библиотек
Rust — это язык системного программирования, который всё чаще используется для создания высоконагруженных и критически важных сервисов. Однако даже самый надёжный код может давать сбои в production-среде. Эффективный мониторинг позволяет вовремя обнаружить проблемы, понять их причину и обеспечить стабильную работу приложения. В этой статье мы рассмотрим основные библиотеки и инструменты для мониторинга приложений на Rust: от сбора метрик до распределённого трейсинга.
1. Сбор и экспорт метрик
Метрики — это числовые показатели состояния приложения (количество запросов, время ответа, использование памяти и т.д.). Для их сбора в Rust используются две основные библиотеки.
1.1. metrics и metrics-exporter-prometheus
Экосистема metrics предоставляет лёгкий и гибкий способ регистрации метрик. Она поддерживает счётчики, гистограммы, датчики и другие типы. Для экспорта в Prometheus используется крейт metrics-exporter-prometheus.
use metrics::{counter, histogram};
use metrics_exporter_prometheus::PrometheusBuilder;
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Настройка HTTP-эндпоинта для Prometheus
let addr: SocketAddr = "0.0.0.0:9000".parse()?;
let builder = PrometheusBuilder::new().with_http_listener(addr);
builder.install()?;
// Регистрация метрик
counter!("http_requests_total", 1);
histogram!("request_duration_seconds", 0.045);
// Запись метрик в фоне
loop {
counter!("http_requests_total", 1);
histogram!("request_duration_seconds", 0.023);
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
}
}
Плюсы: высокая производительность, минимальное потребление памяти, поддержка кастомных экспортёров.
1.2. opentelemetry (метрики)
OpenTelemetry — это универсальный стандарт для сбора телеметрии. Крейт opentelemetry поддерживает метрики, трейсы и логи. Для экспорта в Prometheus используется opentelemetry-prometheus.
use opentelemetry::{global, KeyValue};
use opentelemetry::metrics::MeterProvider;
use opentelemetry_prometheus::PrometheusExporter;
fn init_meter() {
let exporter = PrometheusExporter::default();
let provider = opentelemetry::sdk::metrics::MeterProvider::builder()
.with_reader(exporter)
.build();
global::set_meter_provider(provider);
}
fn main() {
init_meter();
let meter = global::meter("my_app");
let counter = meter.u64_counter("requests").init();
counter.add(1, &[KeyValue::new("method", "GET")]);
}
Плюсы: стандартизация, возможность переключения между бэкендами (Prometheus, Datadog, InfluxDB).
2. Распределённый трейсинг
Трейсинг помогает отслеживать путь запроса через несколько микросервисов. Для Rust лучшим выбором является tracing.
2.1. Крейт tracing и tracing-opentelemetry
Библиотека tracing предоставляет структурированное логирование и трейсинг. Она интегрируется с OpenTelemetry через tracing-opentelemetry.
use tracing::{info, span, Level};
use tracing_subscriber::fmt;
use opentelemetry::global;
use opentelemetry_otlp::WithExportConfig;
fn init_tracer() {
let tracer = opentelemetry_otlp::new_pipeline()
.tracing()
.with_exporter(opentelemetry_otlp::new_exporter().tonic().with_endpoint("http://localhost:4317"))
.install_simple()
.expect("Failed to install OTLP tracer");
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
let subscriber = fmt::Subscriber::builder()
.with_env_filter("info")
.finish()
.with(telemetry);
tracing::subscriber::set_global_default(subscriber).expect("Failed to set subscriber");
}
#[tracing::instrument]
fn process_request(user_id: u64) {
let span = span!(Level::INFO, "handler", user_id = user_id);
let _guard = span.enter();
info!("Processing request");
// ...
}
fn main() {
init_tracer();
process_request(42);
}
Плюсы: минимальное влияние на производительность, поддержка асинхронных контекстов, автоматическое связывание спанов.
3. Логирование
Структурированные логи —