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
//! # Prometheus Push
//!
//! `prometheus_push` works as an extension to prometheus crates like [prometheus](https://crates.io/crates/prometheus) to be able to push non-blocking (default)
//! or blocking to your Prometheus pushgateway and with a less dependent setup of `reqwest` (no `openssl` for example) or with an implementation of your
//! own http client.
//!
//! By default you have to implement the `Push` trait to use it with your choice of http client or you can use the `with_reqwest` feature.
//! This feature already implements `Push` in a `PushClient` that leverages `reqwest` under the hood. Reqwest is setup 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 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 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.
//!
//! ## Example with features `with_reqwest` and `prometheus_crate`
//!
//! ```ignore
//! use prometheus::labels;
//! use prometheus_push::prometheus_crate::PrometheusMetricsPusher;
//! use reqwest::Client;
//! use url::Url;
//!
//! let push_gateway: Url = "<address to your instance>";
//! 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?;
//! ```
//!
//! ## 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::non_blocking::Push;
//!
//! pub struct YourPushClient;
//!
//! #[async_trait::async_trait]
//! 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
//!
//! ## Integration in your `Cargo.toml`
//!
//! Let's say you wanna use it with `reqwest` in an async fashion with the `prometheus` crate, you have to add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! prometheus_push = { version = "<version>", default-features = false, features = ["with_reqwest", "prometheus_crate"] }
//! ```

#[cfg(feature = "blocking")]
pub mod blocking;
#[cfg(feature = "non_blocking")]
pub mod non_blocking;
#[cfg(feature = "prometheus_client_crate")]
pub mod prometheus_client_crate;
#[cfg(feature = "prometheus_crate")]
pub mod prometheus_crate;
#[cfg(feature = "with_reqwest")]
pub mod with_reqwest;

pub mod error;
mod utils;

use std::collections::HashMap;

use url::Url;

use crate::error::Result;

/// `ConvertMetrics` defines the interface for the implementation of your own prometheus logic
/// to incorporate it into [`non_blocking::MetricsPusher`] or [`blocking::MetricsPusher`].
pub trait ConvertMetrics<MF, C, B> {
    /// metric_families_from converts the given collectors to metric families.
    fn metrics_from(&self, collectors: C) -> Result<MF>;

    /// create_push_details creates the input arguments for the [`Push`] clients methods.
    fn create_push_details(
        &self,
        job: &str,
        url: &Url,
        grouping: &HashMap<&str, &str>,
        metrics: MF,
    ) -> Result<(Url, B, String)>;
}