rs-zero 0.1.1

Rust-first microservice framework inspired by go-zero engineering practices
Documentation
use std::time::Instant;

use axum::{
    Router,
    body::Body,
    extract::{MatchedPath, State},
    http::Request,
    middleware::Next,
    response::IntoResponse,
    routing::get,
};

use crate::observability::{HttpMetricLabels, MetricsRegistry};

/// Records request metrics for an axum route.
pub async fn record_metrics_middleware(
    State(registry): State<MetricsRegistry>,
    request: Request<Body>,
    next: Next,
) -> impl IntoResponse {
    let method = request.method().to_string();
    let route = request
        .extensions()
        .get::<MatchedPath>()
        .map(|path| path.as_str().to_string())
        .unwrap_or_else(|| "unknown".to_string());
    let started = Instant::now();
    let response = next.run(request).await;
    let status = response.status().as_u16();
    registry.record_http_request(
        HttpMetricLabels::new(method, route, status),
        started.elapsed(),
    );
    response
}

/// Creates a router exposing Prometheus metrics at `/metrics`.
pub fn metrics_router(registry: MetricsRegistry) -> Router {
    Router::new().route(
        "/metrics",
        get(move || {
            let registry = registry.clone();
            async move { registry.render_prometheus() }
        }),
    )
}