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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//! # Prometheus Push
//!
//! `prometheus_push` works as an extension to prometheus crates like [prometheus](https://crates.io/crates/prometheus) or
//! [prometheus-client](https://crates.io/crates/prometheus-client) to be able to push non-blocking (default) or blocking to your Prometheus
//! pushgateway with a less dependent setup of `reqwest` (no `openssl` for example) or with an implementation of your own http client or even
//! another `prometheus` crate – this whole crate is completely generic so you are free to do whatever you want.
//!
//! If you wanna use it with `reqwest`, `prometheus` or `prometheus-client` crates you literally do not have to implement anything (see
//! below), as those common usages are already implemented as features within this crate.
//!
//! In this crates stripped version you have to implement the `Push` trait (see below) to use it with your choice of
//! http client or –as said– you can use the `with_reqwest` or `with_reqwest_blocking` features. These features already implement `Push` in a
//! `PushClient` that leverages `reqwest` under the hood. Reqwest is set up without default features (minimal set) in this case so it should
//! not interfere with your own applications reqwest setup (e.g. `rust-tls`).
//!
//! Async functionality (feature `non_blocking`) is considered the standard in this crate but you can enable the `blocking` feature to get the
//! implementation without async. You can enable the corresponding blocking `reqwest` implementation with the `with_reqwest_blocking` feature in
//! which case you enable the `blocking` feature of the `reqwest` crate.
//!
//! In terms of the underlying prometheus functionality you have to implement the `ConvertMetrics` trait yourself (see below)
//! or you use the already implemented feature `prometheus_crate` that leverages the [prometheus](https://crates.io/crates/prometheus) crate or
//! `prometheus_client_crate` that uses the [prometheus-client](https://crates.io/crates/prometheus-client) crate.
//!
//! ## Scenarios
//!
//! ### 1. I use `reqwest` and `prometheus` crates in a **non-blocking** fashion
//!
//! In your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! prometheus_push = { version = "<version>", default-features = false, features = ["with_reqwest", "prometheus_crate"] }
//! ```
//!
//! ```ignore
//! use prometheus::labels;
//! use prometheus_push::prometheus_crate::PrometheusMetricsPusher;
//! use reqwest::Client;
//! use url::Url;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusMetricsPusher::from(client, &push_gateway)?;
//! metrics_pusher
//! .push_all(
//! "<your push jobs name>",
//! &labels! { "<label_name>" => "<label_value>" },
//! prometheus::gather(),
//! )
//! .await?;
//!
//! Ok(())
//! }
//! ```
//!
//!### 2. I use `reqwest` and `prometheus` crates in a **blocking** fashion
//!
//!In your `Cargo.toml`:
//!
//!```toml
//![dependencies]
//!prometheus_push = { version = "<version>", default-features = false, features = ["with_reqwest_blocking", "prometheus_crate"] }
//!```
//!```ignore
//!use prometheus::labels;
//! use prometheus_push::prometheus_crate::PrometheusMetricsPusherBlocking;
//! use reqwest::blocking::Client;
//! use url::Url;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusMetricsPusherBlocking::from(client, &push_gateway)?;
//! metrics_pusher
//! .push_all(
//! "<your push jobs name>",
//! &labels! { "<label_name>" => "<label_value>" },
//! prometheus::gather(),
//! )?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### 3. I use `reqwest` and `prometheus-client` crates in a **non-blocking** fashion
//!
//! In your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! prometheus_push = { version = "<version>", default-features = false, features = ["with_reqwest", "prometheus_client_crate"] }
//! ```
//! ```ignore
//! use prometheus_client::encoding::text::encode;
//! use prometheus_push::prometheus_client_crate::PrometheusClientMetricsPusher;
//! use reqwest::Client;
//! use url::Url;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusClientMetricsPusher::create(client, &push_gateway)?;
//! let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
//! let mut metrics = String::new();
//! encode(&mut metrics, ®istry)?;
//!
//! metrics_pusher
//! .push_all(
//! "<your push jobs name>",
//! &grouping,
//! metrics,
//! )
//! .await?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### 4. I use `reqwest` and `prometheus-client` crates in a **blocking** fashion
//!
//! In your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! prometheus_push = { version = "<version>", default-features = false, features = ["with_reqwest_blocking", "prometheus_client_crate"] }
//! ```
//!
//! ```ignore
//! use prometheus_client::encoding::text::encode;
//! use prometheus_push::prometheus_client_crate::PrometheusClientMetricsPusherBlocking;
//! use reqwest::blocking::Client;
//! use url::Url;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusClientMetricsPusherBlocking::create(client, &push_gateway)?;
//! let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
//! let mut metrics = String::new();
//! encode(&mut metrics, ®istry)?;
//!
//! metrics_pusher
//! .push_all(
//! "<your push jobs name>",
//! &grouping,
//! metrics,
//! )?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### 5. I want to implement everything myself
//!
//! In case you wanna implement everything yourself you can do so by implementing the `Push` trait and the `ConvertMetrics` trait.
//!
//! #### Implement `Push` yourself
//!
//! If you are not using reqwest as an http client you are free to implement the `Push` traits two methods yourself. As a guide you can use the
//! implementation of the `with_reqwest` feature (see [here](https://github.com/maoertel/prometheus-push/blob/7fe1946dd143f4870beb80e642b0acb7854a3cb8/src/with_reqwest.rs)).
//! Basically it is as simple as that.
//!
//! ```ignore
//! use prometheus_push::Push;
//!
//! pub struct YourPushClient;
//!
//! impl Push<Vec<u8>> for YourPushClient {
//! async fn push_all(&self, url: &Url, body: Vec<u8>, content_type: &str) -> Result<()> {
//! // implement a PUT request with your client with this body and `content_type` in header
//! }
//!
//! async fn push_add(&self, url: &Url, body: Vec<u8>, content_type: &str) -> Result<()> {
//! // implement a POST request with your client with this body and `content_type` in header
//! }
//! }
//! ```
//!
//! #### Implement `ConvertMetrics` yourself
//!
//! In case you want to use another prometheus client implementation you can implement your own type that implements
//! the `ConvertMetrics` trait to inject it into your instance of `MetricsPusher`.
//!
//! ```ignore
//! impl ConvertMetrics<Vec<YourMetricFamily>, Vec<Box<dyn YourCollector>>, Vec<u8>> for YourMetricsConverter {
//! fn metric_families_from(
//! &self,
//! collectors: Vec<Box<dyn YourCollector>>,
//! ) -> Result<Vec<YourMetricFamily>> {
//! // implement the conversion from your Collectors to your MetricsFamilies, or whatever
//! // your generic `MF` type stands for
//! }
//!
//! fn create_push_details(
//! &self,
//! job: &str,
//! url: &Url,
//! grouping: &HashMap<&str, &str>,
//! metric_families: Vec<YourMetricFamily>,
//! ) -> Result<(Url, Vec<u8>, String)> {
//! // create your push details for the `Push` methods: Url, body and content type
//! }
//! }
//! ```
//!
//! ## Features
//!
//! - `default`: by default async functionality and no reqwest is enabled
//! - `non_blocking`: this ennables the async functionality
//! - `blocking`: on top of the default feature you get the same functionality in a blocking fashion
//! - `with_reqwest`: this feature enables the `non_blocking` feature as well as `reqwest` in minimal configuration and enables the alredy implemented `PushClient`
//! - `with_reqwest_blocking`: like `with_reqwest` but including `blocking` instead of `non_blocking`
//! - `prometheus_crate`: enables the functionality of the [prometheus](https://crates.io/crates/prometheus) crate
//! - `prometheus_client_crate`: enables the functionality of the [prometheus-client](https://crates.io/crates/prometheus-client) crate
//!
use HashMap;
use Url;
use crateResult;
/// `ConvertMetrics` defines the interface for the implementation of your own prometheus logic
/// to incorporate it into [`non_blocking::MetricsPusher`] or [`blocking::MetricsPusher`].