diff --git a/Cargo.toml b/Cargo.toml index 2c1f889..b9e9338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ prost-types = { version = "0.12.0", optional = true } [dev-dependencies] async-std = { version = "1", features = ["attributes"] } +axum = "0.7" criterion = "0.5" http-types = "2" pyo3 = "0.21" diff --git a/examples/axum.rs b/examples/axum.rs new file mode 100644 index 0000000..bf85255 --- /dev/null +++ b/examples/axum.rs @@ -0,0 +1,88 @@ +use axum::body::Body; +use axum::extract::State; +use axum::http::header::CONTENT_TYPE; +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; +use axum::routing::get; +use axum::Router; +use prometheus_client::encoding::text::encode; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::registry::Registry; +use prometheus_client_derive_encode::{EncodeLabelSet, EncodeLabelValue}; +use std::sync::Arc; +use tokio::sync::Mutex; + +#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)] +pub enum Method { + Get, + Post, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] +pub struct MethodLabels { + pub method: Method, +} + +#[derive(Debug)] +pub struct Metrics { + requests: Family, +} + +impl Metrics { + pub fn inc_requests(&self, method: Method) { + self.requests.get_or_create(&MethodLabels { method }).inc(); + } +} + +#[derive(Debug)] +pub struct AppState { + pub registry: Registry, +} + +pub async fn metrics_handler(State(state): State>>) -> impl IntoResponse { + let state = state.lock().await; + let mut buffer = String::new(); + encode(&mut buffer, &state.registry).unwrap(); + + Response::builder() + .status(StatusCode::OK) + .header( + CONTENT_TYPE, + "application/openmetrics-text; version=1.0.0; charset=utf-8", + ) + .body(Body::from(buffer)) + .unwrap() +} + +pub async fn some_handler(State(metrics): State>>) -> impl IntoResponse { + metrics.lock().await.inc_requests(Method::Get); + "okay".to_string() +} + +#[tokio::main] +async fn main() { + let metrics = Metrics { + requests: Family::default(), + }; + let mut state = AppState { + registry: Registry::default(), + }; + state + .registry + .register("requests", "Count of requests", metrics.requests.clone()); + let metrics = Arc::new(Mutex::new(metrics)); + let state = Arc::new(Mutex::new(state)); + + let router = Router::new() + .route("/metrics", get(metrics_handler)) + .with_state(state) + .route("/handler", get(some_handler)) + .with_state(metrics); + let port = 8080; + let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)) + .await + .unwrap(); + + axum::serve(listener, router).await.unwrap(); +}