use prometheus_client::encoding::EncodeLabelValue; use prometheus_client::encoding::{text::encode, EncodeLabelSet}; use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; use prometheus_client::registry::Registry; use std::sync::Arc; use tide::{Middleware, Next, Request, Result}; #[async_std::main] async fn main() -> std::result::Result<(), std::io::Error> { tide::log::start(); let mut registry = Registry::default(); let http_requests_total = Family::::default(); registry.register( "http_requests_total", "Number of HTTP requests", http_requests_total.clone(), ); let middleware = MetricsMiddleware { http_requests_total, }; let mut app = tide::with_state(State { registry: Arc::new(registry), }); app.with(middleware); app.at("/").get(|_| async { Ok("Hello, world!") }); app.at("/metrics") .get(|req: tide::Request| async move { let mut encoded = String::new(); encode(&mut encoded, &req.state().registry).unwrap(); let response = tide::Response::builder(200) .body(encoded) .content_type("application/openmetrics-text; version=1.0.0; charset=utf-8") .build(); Ok(response) }); app.listen("127.0.0.1:8080").await?; Ok(()) } #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] struct Labels { method: Method, path: String, } #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)] enum Method { Get, Put, } #[derive(Clone)] struct State { registry: Arc, } #[derive(Default)] struct MetricsMiddleware { http_requests_total: Family, } #[tide::utils::async_trait] impl Middleware for MetricsMiddleware { async fn handle(&self, req: Request, next: Next<'_, State>) -> Result { let method = match req.method() { http_types::Method::Get => Method::Get, http_types::Method::Put => Method::Put, _ => todo!(), }; let path = req.url().path().to_string(); let _count = self .http_requests_total .get_or_create(&Labels { method, path }) .inc(); let res = next.run(req).await; Ok(res) } }