prom_timer_macro/
lib.rs

1//! Macros for [`prom-timer`].
2//!
3//! [`prom-timer`]: https://crates.io/crates/prom-timer
4
5use proc_macro::TokenStream;
6use quote::quote;
7use std::collections::vec_deque::VecDeque;
8use syn::parse::{Parse, ParseStream, Result};
9use syn::punctuated::Punctuated;
10use syn::{parse_macro_input, Expr, ItemFn, Token};
11
12struct Args {
13    metric: Expr,
14    tags: Vec<Expr>,
15}
16
17impl Parse for Args {
18    fn parse(input: ParseStream) -> Result<Self> {
19        let mut params: VecDeque<Expr> = Punctuated::<Expr, Token![,]>::parse_terminated(input)?
20            .into_iter()
21            .collect();
22
23        let metric = params.pop_front().unwrap();
24
25        Ok(Args {
26            metric,
27            tags: params.into_iter().collect(),
28        })
29    }
30}
31
32
33///
34/// Decorator for synchronous and asynchronous functions to measure their execution time with
35/// RAII [`prom-timer`]
36///
37/// As the error message says, handler function needs to be async.
38///
39/// ```
40/// use prometheus::{self, HistogramVec, histogram_opts};
41///
42/// let timer = HistogramVec::new(
43///             histogram_opts!("timer", "Timer")
44///                 .namespace("api_v2")
45///                 .const_labels(labels.clone())
46///                 .buckets(
47///                     [
48///                         0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1.0, 2.0,
49///                        3.0, 4.0, 5.0, 10.0,
50///                     ]
51///                     .into(),
52///                 ),
53///             &["tag"],
54///         )
55///         .unwrap();
56///
57/// registry.register(Box::new(timer.clone())).unwrap();
58///
59/// #[timer(timer, "f")]
60/// async fn f() {
61///     // ... Some work here.
62/// }
63///
64/// ```
65/// `f()` execution time will be stored as timer histogram entry with tag `f`
66///
67#[proc_macro_attribute]
68pub fn timer(args: TokenStream, input: TokenStream) -> TokenStream {
69    let input = parse_macro_input!(input as ItemFn);
70
71    let args = parse_macro_input!(args as Args);
72
73    let ItemFn {
74        attrs,
75        vis,
76        sig,
77        block,
78    } = input;
79
80    let metric = args.metric;
81    let tags = args.tags;
82    let stmts = &block.stmts;
83
84    let expanded = quote! {
85        #(#attrs)* #vis #sig {
86            let _t = prom_timer::Timer::new(#metric, &[#(#tags)*]);
87            #(#stmts)*
88        }
89    };
90
91    TokenStream::from(expanded)
92}