#![doc = include_str!("../README.md")] pub mod query; pub mod result; use prometheus_http_query::Client; use query::IntoQuery; use reqwest::header::HeaderValue; use result::{IntoQryResult, QryResult}; use url::Url; /// The primary way to send queries and get deserialized responses from the metrics server /// /// The default instance uses no authentication, initializes it's own reqwest client and the /// server url is set to "http://127.0.0.1:9090" and sends requests using the GET HTTP method. #[derive(Default, Clone)] pub struct QueryManager { auth: Auth, client: Client, timeout: Option<i64>, method: Method, } impl QueryManager { /// Build a new QueryManager using a valid base URL (without Prometheus API path) pub fn new(url: Url) -> Self { QueryManager { #[allow(clippy::unwrap_used)] // url is already validated client: Client::try_from(url.as_str()).expect("unexpected failure"), ..Default::default() } } /// Build a new QueryManager using a valid base URL (without Prometheus API path) and an existing reqwest Client pub fn from_client(url: Url, client: reqwest::Client) -> Self { QueryManager { auth: Default::default(), #[allow(clippy::unwrap_used)] // url is already validated client: Client::from(client, url.as_str()).expect("unexpected failure"), ..Default::default() } } /// Set authentication method (no auth is used by default) /// /// Currently only supports bearer tokens pub fn auth(&mut self, auth: Auth) -> &mut Self { self.auth = auth; self } /// Set timeout for Prometheus queries pub fn timeout(&mut self, timeout: i64) -> &mut Self { self.timeout.replace(timeout); self } /// Set HTTP method to use to send queries to the server (default: `Get`) pub fn method(&mut self, method: Method) -> &mut Self { self.method = method; self } /// Send a query to the Prometheus server and retreived deserialized data /// /// This method accepts any type that implements the `IntoQuery` trait. /// The trait is implemented for `&str`, `String`, `&String`, and __mquery's__ /// internal types such as [`query::Metric`], [`query::Scalar`] and others that result /// from the query builder API. pub async fn query<Q: IntoQuery>(&self, query: Q) -> QryResult { let mut builder = self.client.query(query.into_query().as_ref()); if let Some((name, val)) = self.auth.get_header() { builder = builder.header(name, val); } if let Some(timeout) = self.timeout.as_ref() { builder = builder.timeout(*timeout); } match self.method { Method::Get => builder.get().await.into_qry_result(), Method::Post => builder.post().await.into_qry_result(), } } /// Send a ranged query to the Prometheus server and retreived deserialized data /// /// This method accepts any type that implements the `IntoQuery` trait. /// The trait is implemented for `&str`, `String`, `&String`, and __mquery's__ /// internal types such as [`query::Metric`], [`query::Scalar`] and others that result /// from the query builder API. pub async fn query_range<Q: IntoQuery>( &self, query: Q, start: i64, end: i64, step: f64, ) -> QryResult { let mut builder = self .client .query_range(query.into_query().as_ref(), start, end, step); if let Some((name, val)) = self.auth.get_header() { builder = builder.header(name, val); } if let Some(timeout) = self.timeout.as_ref() { builder = builder.timeout(*timeout); } match self.method { Method::Get => builder.get().await.into_qry_result(), Method::Post => builder.post().await.into_qry_result(), } } } // TODO: Add support for basic auth as well /// Authentication method /// /// Used in [`QueryManager::auth`] to set the authentication type #[derive(Default, Clone, Debug)] pub enum Auth { #[default] None, Bearer(String), } impl Auth { const AUTH_HEADER: &'static str = "Authorization"; fn get_header(&self) -> Option<(&'static str, HeaderValue)> { match self { Auth::None => None, Auth::Bearer(token) => Some(( Self::AUTH_HEADER, #[allow(clippy::unwrap_used)] // building from valid chars format!("Bearer {}", token) .parse() .expect("unexpected failure"), )), } } } /// HTTP method to use to send queries /// /// This is used by the [`QueryManager::method`] method to set the HTTP /// method used to send queries to the server. #[derive(Clone, Copy, Debug, Default)] pub enum Method { #[default] Get, Post, } // Private trait used to seal other traits to disallow users from implementing // them directly pub(crate) mod seal { pub(crate) trait Sealed {} }