prometheus_http_query/lib.rs
1//! This crate provides an interface to the [Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/).
2//! The [`Client`] is used to interact with a Prometheus server. It is basically a wrapper around a [`reqwest::Client`] and implements
3//! additional methods to execute PromQL queries and fetch metadata.
4//!
5//! # Usage
6//!
7//! The following code contains just a few examples. See [`Client`] for the complete set of available functions.
8//!
9//!
10//! ## Initialize a client
11//!
12//! The [`Client`] can be constructed in various ways depending on your need to add customizations.
13//!
14//! ```rust
15//! use prometheus_http_query::Client;
16//! use std::str::FromStr;
17//!
18//! // In the most general case the default implementation is used to create the client.
19//! // Requests will be sent to "http://127.0.0.1:9090 (the default listen address and port of the Prometheus server).
20//! let client = Client::default();
21//!
22//! // Provide an alternative URL if you need to. The URL will be checked for correctness.
23//! use std::convert::TryFrom;
24//! let client = Client::try_from("https://prometheus.example.com").unwrap();
25//!
26//! // The greatest flexibility is offered by initializing a reqwest::Client first with
27//! // all needed customizations and passing it along.
28//! let client = {
29//! let c = reqwest::Client::builder().no_proxy().build().unwrap();
30//! Client::from(c, "https://prometheus.example.com").unwrap();
31//! };
32//! ```
33//!
34//! ## Execute PromQL queries
35//!
36//! ```rust
37//! use prometheus_http_query::{Client, Selector};
38//!
39//! #[tokio::main(flavor = "current_thread")]
40//! async fn main() -> Result<(), anyhow::Error> {
41//! let client = Client::default();
42//!
43//! // Execute a query using HTTP GET.
44//! let q = "topk by (code) (5, prometheus_http_requests_total)";
45//! let response = client.query(q).get().await?;
46//! assert!(response.data().as_vector().is_some());
47//!
48//! let q = r#"sum(prometheus_http_requests_total{code="200"})"#;
49//! let response = client.query(q).get().await?;
50//! let result = response.data().as_vector().expect("Expected result of type vector");
51//!
52//! if !result.is_empty() {
53//! let first = result.first().unwrap();
54//! println!("Received a total of {} HTTP requests", first.sample().value());
55//! }
56//!
57//! // HTTP POST is also supported.
58//! let q = "topk by (code) (5, prometheus_http_requests_total)";
59//! let response = client.query(q).post().await?;
60//! let result = response.data().as_vector().is_some();
61//!
62//! Ok(())
63//! }
64//! ```
65//!
66//! ## Metadata queries
67//!
68//! Retrieve a list of time series that match a certain label set by providing one or more series [`Selector`]s.
69//! More metadata queries are available, e.g. methods to retrieve label names and values.
70//!
71//! ```rust
72//! use prometheus_http_query::{Client, Selector};
73//!
74//! #[tokio::main(flavor = "current_thread")]
75//! async fn main() -> Result<(), anyhow::Error> {
76//! let client = Client::default();
77//!
78//! let s1 = Selector::new()
79//! .eq("handler", "/api/v1/query");
80//!
81//! let s2 = Selector::new()
82//! .eq("job", "node")
83//! .regex_eq("mode", ".+");
84//!
85//! let response = client.series(&[s1, s2])?.get().await;
86//!
87//! assert!(response.is_ok());
88//!
89//! Ok(())
90//! }
91//! ```
92//!
93//! ## Rules & Alerts
94//!
95//! Retrieve recording/alerting rules and active alerts.
96//!
97//! ```rust
98//! use prometheus_http_query::{Client, RuleKind};
99//!
100//! #[tokio::main(flavor = "current_thread")]
101//! async fn main() -> Result<(), anyhow::Error> {
102//! let client = Client::default();
103//!
104//! let response = client.rules().get().await;
105//!
106//! assert!(response.is_ok());
107//!
108//! // Only request alerting rules instead:
109//! let response = client.rules().kind(RuleKind::Alerting).get().await;
110//!
111//! assert!(response.is_ok());
112//!
113//! // Request active alerts:
114//! let response = client.alerts().await;
115//!
116//! assert!(response.is_ok());
117//!
118//! Ok(())
119//! }
120//! ```
121//!
122//! ## Convenience functions for one-off requests
123//!
124//! ```rust
125//! use prometheus_http_query::{query, runtime_information};
126//!
127//! #[tokio::main(flavor = "current_thread")]
128//! async fn main() -> Result<(), anyhow::Error> {
129//! let q = "topk by (code) (5, prometheus_http_requests_total)";
130//! let response = query("http://localhost:9090", q)?.get().await?;
131//!
132//! assert!(response.data().as_vector().is_some());
133//!
134//! let response = runtime_information("http://localhost:9090").await;
135//!
136//! assert!(response.is_ok());
137//!
138//! Ok(())
139//! }
140//! ```
141//!
142//! # Features
143//!
144//! At this point all available feature flags pertain to the [`Client`]s TLS configuration. They enable feature flags of
145//! the `reqwest` crate by the same name.<br>
146//! See the [reqwest documentation](https://docs.rs/reqwest/0.11.14/reqwest/index.html#optional-features) for details on
147//! these feature flags.<br>
148//! Also make sure that default features of `prometheus-http-query` are disabled if you choose a TLS library other than
149//! the default:
150//!
151//! `prometheus-http-query = { version = "0.7", default-features = false, features = ["rustls-tls"] }`
152//!
153//! # Compatibility
154//!
155//! The crate is generally compatible with Prometheus server >=2.30. However individual [`Client`] methods might
156//! only work with the latest Prometheus server version when the corresponding API endpoint has only recently
157//! been introduced.<br>
158//! The minimum recommended Prometheus server version is v2.46.<br>
159//! Also some features may only work when the Prometheus server is started with certain flags. An example
160//! are query statistics that can be enabled via [`RangeQueryBuilder::stats`]. The response
161//! will not contain per-step stats unless Prometheus is started with `--enable-feature=promql-per-step-stats`.
162//!
163//! # Error handling
164//!
165//! All [`Client`] methods that interact with the Prometheus API return a `Result`. Also each request to the API
166//! may fail at different stages. In general the following approach is taken to return the most significant
167//! error to the caller:
168//! - When the server's response contains header `Content-Type: application/json` (or variants thereof) the
169//! JSON body is parsed to the target type, regardless of the HTTP status code, since Prometheus returns elaborate
170//! error messages within the HTTP body in any case.
171//! A JSON response having `"status": "success"` is deserialized to the target type of this function and returned
172//! within `Result::Ok`. A response with `"status": "error"` is instead deserialized to a [`error::PrometheusError`]
173//! and returned within `Result::Err`.
174//! - Any other server HTTP 4xx/5xx responses without the proper header indicating a JSON-encoded body are
175//! returned as [`Error::Client`] within `Result::Err`. For example, this may happen when an intermediate proxy server
176//! fails to handle a request and subsequently return a plain text error message and a non-2xx HTTP status code.
177//!
178//! # Supported operations
179//!
180//! - [x] Execute instant and range queries (GET or POST) and properly parse the results (vector/matrix/scalar)
181//! - [x] Execute series metadata queries
182//! - [x] Execute label metadata queries (names/values)
183//! - [x] Retrieve target discovery status
184//! - [x] Retrieve alerting + recording rules
185//! - [x] Retrieve active alerts
186//! - [x] Retrieve configured flags & values
187//! - [x] Query target metadata
188//! - [x] Query metric metadata
189//! - [x] Query alertmanager service discovery status
190//! - [x] Prometheus server health and readiness
191//! - [x] Prometheus server flags
192//! - [x] Prometheus server build information
193//! - [x] Prometheus server runtime information
194//! - [ ] Prometheus server config
195//!
196//! # Limitations
197//!
198//! * Some [`Client`] methods may not work with older versions of the Prometheus server.
199//! * The [String](https://prometheus.io/docs/prometheus/latest/querying/api/#strings) result type is not supported
200//! as it is currently not used by Prometheus.
201//! * Warnings contained in an API response will be ignored.
202mod client;
203mod direct;
204pub mod error;
205pub mod response;
206mod selector;
207mod util;
208pub use self::client::{
209 Client, InstantQueryBuilder, LabelNamesQueryBuilder, LabelValuesQueryBuilder,
210 MetricMetadataQueryBuilder, RangeQueryBuilder, RulesQueryBuilder, SeriesQueryBuilder,
211 TargetMetadataQueryBuilder,
212};
213pub use self::direct::*;
214pub use self::error::Error;
215pub use self::selector::Selector;
216pub use self::util::RuleKind;
217pub use self::util::TargetState;