mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-17 00:00:16 +02:00
92 lines
2.6 KiB
Rust
92 lines
2.6 KiB
Rust
//! Someday tower-http will hopefully have a metrics middleware, until then you can track
|
|
//! metrics like this.
|
|
//!
|
|
//! Run with
|
|
//!
|
|
//! ```not_rust
|
|
//! cargo run -p example-prometheus-metrics
|
|
//! ```
|
|
|
|
use axum::{extract::MatchedPath, http::Request, response::IntoResponse, routing::get, Router};
|
|
use axum_extra::middleware::{self, Next};
|
|
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};
|
|
use std::{
|
|
future::ready,
|
|
net::SocketAddr,
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// Set the RUST_LOG, if it hasn't been explicitly defined
|
|
if std::env::var_os("RUST_LOG").is_none() {
|
|
std::env::set_var("RUST_LOG", "example_todos=debug,tower_http=debug")
|
|
}
|
|
tracing_subscriber::fmt::init();
|
|
|
|
let recorder_handle = setup_metrics_recorder();
|
|
|
|
let app = Router::new()
|
|
.route("/fast", get(|| async {}))
|
|
.route(
|
|
"/slow",
|
|
get(|| async {
|
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
}),
|
|
)
|
|
.route("/metrics", get(move || ready(recorder_handle.render())))
|
|
.route_layer(middleware::from_fn(track_metrics));
|
|
|
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
|
tracing::debug!("listening on {}", addr);
|
|
axum::Server::bind(&addr)
|
|
.serve(app.into_make_service())
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
fn setup_metrics_recorder() -> PrometheusHandle {
|
|
const EXPONENTIAL_SECONDS: &[f64] = &[
|
|
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
|
|
];
|
|
|
|
let recorder = PrometheusBuilder::new()
|
|
.set_buckets_for_metric(
|
|
Matcher::Full("http_requests_duration_seconds".to_string()),
|
|
EXPONENTIAL_SECONDS,
|
|
)
|
|
.build();
|
|
|
|
let recorder_handle = recorder.handle();
|
|
|
|
metrics::set_boxed_recorder(Box::new(recorder)).unwrap();
|
|
|
|
recorder_handle
|
|
}
|
|
|
|
async fn track_metrics<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
|
let start = Instant::now();
|
|
let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
|
|
matched_path.as_str().to_owned()
|
|
} else {
|
|
req.uri().path().to_owned()
|
|
};
|
|
let method = req.method().clone();
|
|
|
|
let response = next.run(req).await;
|
|
|
|
let latency = start.elapsed().as_secs_f64();
|
|
let status = response.status().as_u16().to_string();
|
|
|
|
let labels = [
|
|
("method", method.to_string()),
|
|
("path", path),
|
|
("status", status),
|
|
];
|
|
|
|
metrics::increment_counter!("http_requests_total", &labels);
|
|
metrics::histogram!("http_requests_duration_seconds", latency, &labels);
|
|
|
|
response
|
|
}
|