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}