@@ -24,6 +24,13 @@ lazy_static! {
2424 . build( )
2525 . unwrap( ) ;
2626}
27+ #[ cfg( feature = "push-async" ) ]
28+ lazy_static ! {
29+ static ref ASYNC_HTTP_CLIENT : reqwest:: Client = reqwest:: Client :: builder( )
30+ . timeout( REQWEST_TIMEOUT_SEC )
31+ . build( )
32+ . unwrap( ) ;
33+ }
2734
2835/// `BasicAuthentication` holder for supporting `push` to Pushgateway endpoints
2936/// using Basic access authentication.
@@ -50,6 +57,7 @@ pub struct BasicAuthentication {
5057/// Note that all previously pushed metrics with the same job and other grouping
5158/// labels will be replaced with the metrics pushed by this call. (It uses HTTP
5259/// method 'PUT' to push to the Pushgateway.)
60+ #[ cfg( feature = "push" ) ]
5361pub fn push_metrics < S : BuildHasher > (
5462 job : & str ,
5563 grouping : HashMap < String , String , S > ,
@@ -60,9 +68,24 @@ pub fn push_metrics<S: BuildHasher>(
6068 push ( job, grouping, url, mfs, "PUT" , basic_auth)
6169}
6270
71+ /// Functions just like `push_metrics`, except the metrics are pushed
72+ /// asynchronously.
73+ /// Requires the feature `push-async`.
74+ #[ cfg( feature = "push-async" ) ]
75+ pub async fn push_metrics_async < S : BuildHasher > (
76+ job : & str ,
77+ grouping : HashMap < String , String , S > ,
78+ url : & str ,
79+ mfs : Vec < proto:: MetricFamily > ,
80+ basic_auth : Option < BasicAuthentication > ,
81+ ) -> Result < ( ) > {
82+ push_async ( job, grouping, url, mfs, "PUT" , basic_auth) . await
83+ }
84+
6385/// `push_add_metrics` works like `push_metrics`, but only previously pushed
6486/// metrics with the same name (and the same job and other grouping labels) will
6587/// be replaced. (It uses HTTP method 'POST' to push to the Pushgateway.)
88+ #[ cfg( feature = "push" ) ]
6689pub fn push_add_metrics < S : BuildHasher > (
6790 job : & str ,
6891 grouping : HashMap < String , String , S > ,
@@ -73,16 +96,26 @@ pub fn push_add_metrics<S: BuildHasher>(
7396 push ( job, grouping, url, mfs, "POST" , basic_auth)
7497}
7598
99+ /// `push_add_metrics_async` works like `push_metrics`, but async.
100+ #[ cfg( feature = "push-async" ) ]
101+ pub async fn push_add_metrics_async < ' a , S : BuildHasher > (
102+ job : & ' a str ,
103+ grouping : HashMap < String , String , S > ,
104+ url : & ' a str ,
105+ mfs : Vec < proto:: MetricFamily > ,
106+ basic_auth : Option < BasicAuthentication > ,
107+ ) -> Result < ( ) > {
108+ push ( job, grouping, url, mfs, "POST" , basic_auth)
109+ }
110+
76111const LABEL_NAME_JOB : & str = "job" ;
77112
78- fn push < S : BuildHasher > (
113+ fn configure_push < S : BuildHasher > (
79114 job : & str ,
80115 grouping : HashMap < String , String , S > ,
81116 url : & str ,
82117 mfs : Vec < proto:: MetricFamily > ,
83- method : & str ,
84- basic_auth : Option < BasicAuthentication > ,
85- ) -> Result < ( ) > {
118+ ) -> Result < ( String , impl Encoder , Vec < u8 > ) > {
86119 // Suppress clippy warning needless_pass_by_value.
87120 let grouping = grouping;
88121
@@ -145,7 +178,18 @@ fn push<S: BuildHasher>(
145178 // Ignore error, `no metrics` and `no name`.
146179 let _ = encoder. encode ( & [ mf] , & mut buf) ;
147180 }
181+ Ok ( ( push_url, encoder, buf) )
182+ }
148183
184+ fn push < S : BuildHasher > (
185+ job : & str ,
186+ grouping : HashMap < String , String , S > ,
187+ url : & str ,
188+ mfs : Vec < proto:: MetricFamily > ,
189+ method : & str ,
190+ basic_auth : Option < BasicAuthentication > ,
191+ ) -> Result < ( ) > {
192+ let ( push_url, encoder, buf) = configure_push ( job, grouping, url, mfs) ?;
149193 let mut builder = HTTP_CLIENT
150194 . request (
151195 Method :: from_str ( method) . unwrap ( ) ,
@@ -159,18 +203,49 @@ fn push<S: BuildHasher>(
159203 }
160204
161205 let response = builder. send ( ) . map_err ( |e| Error :: Msg ( format ! ( "{}" , e) ) ) ?;
206+ handle_push_response ( response. status ( ) , push_url)
207+ }
162208
163- match response. status ( ) {
209+ /// Requires the feature `push-async`.
210+ #[ cfg( feature = "push-async" ) ]
211+ async fn push_async < S : BuildHasher > (
212+ job : & str ,
213+ grouping : HashMap < String , String , S > ,
214+ url : & str ,
215+ mfs : Vec < proto:: MetricFamily > ,
216+ method : & str ,
217+ basic_auth : Option < BasicAuthentication > ,
218+ ) -> Result < ( ) > {
219+ let ( push_url, encoder, buf) = configure_push ( job, grouping, url, mfs) ?;
220+ let mut builder = ASYNC_HTTP_CLIENT
221+ . request (
222+ Method :: from_str ( method) . unwrap ( ) ,
223+ Url :: from_str ( & push_url) . unwrap ( ) ,
224+ )
225+ . header ( CONTENT_TYPE , encoder. format_type ( ) )
226+ . body ( buf) ;
227+
228+ if let Some ( BasicAuthentication { username, password } ) = basic_auth {
229+ builder = builder. basic_auth ( username, Some ( password) ) ;
230+ }
231+
232+ let response = builder. send ( ) . await . map_err ( |e| Error :: Msg ( format ! ( "{}" , e) ) ) ?;
233+ handle_push_response ( response. status ( ) , push_url)
234+ }
235+
236+ fn handle_push_response ( status : StatusCode , push_url : String ) -> Result < ( ) > {
237+ match status {
164238 StatusCode :: ACCEPTED => Ok ( ( ) ) ,
165239 StatusCode :: OK => Ok ( ( ) ) ,
166240 _ => Err ( Error :: Msg ( format ! (
167241 "unexpected status code {} while pushing to {}" ,
168- response . status( ) ,
242+ status,
169243 push_url
170244 ) ) ) ,
171245 }
172246}
173247
248+ #[ cfg( feature = "push" ) ]
174249fn push_from_collector < S : BuildHasher > (
175250 job : & str ,
176251 grouping : HashMap < String , String , S > ,
@@ -188,8 +263,28 @@ fn push_from_collector<S: BuildHasher>(
188263 push ( job, grouping, url, mfs, method, basic_auth)
189264}
190265
266+ /// Requires the feature `push-async`.
267+ #[ cfg( feature = "push-async" ) ]
268+ async fn push_from_collector_async < ' a , S : BuildHasher > (
269+ job : & ' a str ,
270+ grouping : HashMap < String , String , S > ,
271+ url : & ' a str ,
272+ collectors : Vec < Box < dyn Collector > > ,
273+ method : & ' a str ,
274+ basic_auth : Option < BasicAuthentication > ,
275+ ) -> Result < ( ) > {
276+ let registry = Registry :: new ( ) ;
277+ for bc in collectors {
278+ registry. register ( bc) ?;
279+ }
280+
281+ let mfs = registry. gather ( ) ;
282+ push_async ( job, grouping, url, mfs, method, basic_auth) . await
283+ }
284+
191285/// `push_collector` push metrics collected from the provided collectors. It is
192286/// a convenient way to push only a few metrics.
287+ #[ cfg( feature = "push" ) ]
193288pub fn push_collector < S : BuildHasher > (
194289 job : & str ,
195290 grouping : HashMap < String , String , S > ,
@@ -200,8 +295,24 @@ pub fn push_collector<S: BuildHasher>(
200295 push_from_collector ( job, grouping, url, collectors, "PUT" , basic_auth)
201296}
202297
203- /// `push_add_collector` works like `push_add_metrics`, it collects from the
298+ /// `push_collector_async` is just an async version of `push_collector`.
299+ /// Pushes metrics collected from the provided collectors. It is
300+ /// a convenient way to push only a few metrics.
301+ /// Requires the feature `push-async`.
302+ #[ cfg( feature = "push-async" ) ]
303+ pub async fn push_collector_async < ' a , S : BuildHasher > (
304+ job : & ' a str ,
305+ grouping : HashMap < String , String , S > ,
306+ url : & ' a str ,
307+ collectors : Vec < Box < dyn Collector > > ,
308+ basic_auth : Option < BasicAuthentication > ,
309+ ) -> Result < ( ) > {
310+ push_from_collector_async ( job, grouping, url, collectors, "PUT" , basic_auth) . await
311+ }
312+
313+ /// `push_add_collector` works like `push_add_collector`, it collects from the
204314/// provided collectors. It is a convenient way to push only a few metrics.
315+ #[ cfg( feature = "push" ) ]
205316pub fn push_add_collector < S : BuildHasher > (
206317 job : & str ,
207318 grouping : HashMap < String , String , S > ,
@@ -212,6 +323,21 @@ pub fn push_add_collector<S: BuildHasher>(
212323 push_from_collector ( job, grouping, url, collectors, "POST" , basic_auth)
213324}
214325
326+ /// `push_add_collector_async` works like `push_add_collector`, but async.
327+ /// It collects from the provided collectors. It is a convenient way to push
328+ /// only a few metrics.
329+ /// Requires the feature `push-async`.
330+ #[ cfg( feature = "push-async" ) ]
331+ pub async fn push_add_collector_async < ' a , S : BuildHasher > (
332+ job : & ' a str ,
333+ grouping : HashMap < String , String , S > ,
334+ url : & ' a str ,
335+ collectors : Vec < Box < dyn Collector > > ,
336+ basic_auth : Option < BasicAuthentication > ,
337+ ) -> Result < ( ) > {
338+ push_from_collector_async ( job, grouping, url, collectors, "POST" , basic_auth) . await
339+ }
340+
215341const DEFAULT_GROUP_LABEL_PAIR : ( & str , & str ) = ( "instance" , "unknown" ) ;
216342
217343/// `hostname_grouping_key` returns a label map with the only entry
0 commit comments