use hyper::{ Response, Body, Request, Server, header::{CONTENT_TYPE}, service::{make_service_fn, service_fn}, }; use std::net::ToSocketAddrs; use prometheus::{Encoder, TextEncoder}; use log::{info,error}; use serde::Deserialize; #[derive(Clone, Debug, Deserialize)] /// Options for the monitoring service pub struct MonitoringConfiguration { enabled: bool, address: Option, port: Option, } /// Handler for the hyper http server async fn serve_metrics(_request: Request) -> Result, hyper::Error> { let encoder = TextEncoder::new(); let metrics = prometheus::gather(); let mut buffer = vec![]; encoder.encode(&metrics, &mut buffer).unwrap(); let response = Response::builder() .status(200) .header(CONTENT_TYPE, encoder.format_type()) .body(Body::from(buffer)) .unwrap(); Ok(response) } /// Starts a monitoring server on the requested port pub fn start_monitoring(configuration: &MonitoringConfiguration) { let config = configuration.clone(); tokio::task::spawn(async move { if config.enabled { let address = format!("{}:{}", config.address.expect("a listening address must be specified for the metrics server"), config.port.expect("a listening port must be specified for the metrics server") ); info!("Starting monitoring server on {}", address); let listen_address = address .to_socket_addrs() .unwrap() .next() .unwrap(); let server = Server::bind(&listen_address).serve(make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(serve_metrics)) })); if let Err(e) = server.await { error!("failed to start the monitoring server {}", e); } } }); }