1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! This crate provides an interface to the [Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/) and leverage Rust's type system in the process where applicable.
//!
//! The [Client] uses as [reqwest::Client] as HTTP client internally as you will see in the usage section. Thus its features and limitations also apply to this library.
//!
//! # Usage
//!
//! The following code contains just a few examples. See [Client] for the complete set of query functions.
//!
//!
//! ## Initialize a client
//!
//! The [Client] can be constructed in various ways depending on your need to add customizations.
//!
//! ```rust
//! use prometheus_http_query::Client;
//! use std::str::FromStr;
//!
//! // In the most general case the default implementation is used to create the client.
//! // Requests will be sent to "http://127.0.0.1:9090 (the default listen address and port of the Prometheus server).
//! let client = Client::default();
//!
//! // Provide an alternative URL if you need to. The URL will be checked for correctness.
//! use std::convert::TryFrom;
//! let client = Client::try_from("https://prometheus.example.com").unwrap();
//!
//! // The greatest flexibility is offered by initializing a reqwest::Client first with
//! // all needed customizations and passing it along.
//! let client = {
//!     let c = reqwest::Client::builder().no_proxy().build().unwrap();
//!     Client::from(c, "https://prometheus.example.com").unwrap();
//! };
//! ```
//!
//! ## Execute PromQL queries
//!
//! ```rust
//! use prometheus_http_query::{Client, Error, Selector};
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), Error> {
//!     let client = Client::default();
//!
//!     let q = "topk by (code) (5, prometheus_http_requests_total)";
//!     let response = client.query(q, None, None).await?;
//!     assert!(response.as_instant().is_some());
//!
//!     let q = r#"sum(prometheus_http_requests_total{code="200"})"#;
//!     let response = client.query(q, None, None).await?;
//!     let result = response.as_instant();
//!
//!     if matches!(result, Some(x) if x.first().is_some()) {
//!         let first = result.unwrap().first().unwrap();
//!         println!("Received a total of {} HTTP requests", first.sample().value());
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Metadata queries
//!
//! Retrieve a list of time series that match a certain label set by providing one or more series [Selector]s.
//!
//! ```rust
//! use prometheus_http_query::{Client, Error, Selector};
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), Error> {
//!     let client = Client::default();
//!
//!     let s1 = Selector::new()
//!         .eq("handler", "/api/v1/query");
//!
//!     let s2 = Selector::new()
//!         .eq("job", "node")
//!         .regex_eq("mode", ".+");
//!
//!     let response = client.series(&[s1, s2], None, None).await;
//!
//!     assert!(response.is_ok());
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Rules & Alerts
//!
//! Retrieve recording/alerting rules and active alerts.
//!
//! ```rust
//! use prometheus_http_query::{Client, Error, RuleType};
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), Error> {
//!     let client = Client::default();
//!
//!     let response = client.rules(None).await;
//!
//!     assert!(response.is_ok());
//!
//!     // Only request alerting rules instead:
//!     let response = client.rules(Some(RuleType::Alert)).await;
//!
//!     assert!(response.is_ok());
//!
//!     // Request active alerts:
//!     let response = client.alerts().await;
//!
//!     assert!(response.is_ok());
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Convenience functions for one-off requests
//!
//! ```rust
//! use prometheus_http_query::{Error, query, runtime_information};
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), Error> {
//!     let q = "topk by (code) (5, prometheus_http_requests_total)";
//!     let response = query("http://localhost:9090", q, None, None).await?;
//!
//!     assert!(response.as_instant().is_some());
//!
//!     let response = runtime_information("http://localhost:9090").await;
//!
//!     assert!(response.is_ok());
//!
//!     Ok(())
//! }
//! ```
//!
//! # Compatibility
//!
//! See the `README` for details on this matter.
//!
//! # Supported operations
//!
//! - [x] Execute instant and range queries and properly parse the results (vector/matrix/scalar)
//! - [x] Execute series metadata queries
//! - [x] Execute label metadata queries (names/values)
//! - [x] Retrieve target discovery status
//! - [x] Retrieve alerting + recording rules
//! - [x] Retrieve active alerts
//! - [x] Retrieve configured flags & values
//! - [x] Query target metadata
//! - [x] Query metric metadata
//! - [x] Query alertmanager service discovery status
//! - [x] Prometheus server flags
//! - [x] Prometheus server build information
//! - [x] Prometheus server runtime information
//! - [ ] Prometheus server config
//!
//! # Notes
//!
//! ## On parsing an error handling
//!
//! If the JSON response from the Prometheus HTTP API indicates an error (field `status` == `"error"`),
//! then the contents of both fields `errorType` and `error` are captured and then returned by the client
//! as a variant of the [Error] enum, just as any HTTP errors (non-200) that may indicate a problem
//! with the provided query string. Thus any syntax problems etc. that cannot be caught at compile time
//! or before executing the query will at least be propagated as returned by the HTTP API.
//!
//! # Limitations
//!
//! * Some [Client] methods may not work with older versions of the Prometheus server
//! * The [String](https://prometheus.io/docs/prometheus/latest/querying/api/#strings) result type is not supported
//! * Warnings contained in a API response will be ignored
mod client;
mod direct;
mod error;
pub mod response;
mod selector;
mod util;
pub use self::client::Client;
pub use self::direct::*;
pub use self::error::Error;
pub use self::selector::Selector;
pub use self::util::RuleType;
pub use self::util::TargetState;