fuel_indexer_macro_utils/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro_error::proc_macro_error;
5use quote::quote;
6use syn::{parse_macro_input, ItemFn};
7
8fn process_with_prometheus_metrics(input: TokenStream) -> TokenStream {
9    let ast = parse_macro_input!(input as ItemFn);
10    let fn_name = &ast.sig.ident;
11    let label = fn_name.to_string();
12    let fn_inputs = &ast.sig.inputs;
13    let fn_output = &ast.sig.output;
14    let fn_vis = &ast.vis;
15    let block = &ast.block;
16
17    let (asyncness, awaitness) = if ast.sig.asyncness.is_none() {
18        (quote! {}, quote! {})
19    } else {
20        (quote! {async}, quote! {.await})
21    };
22
23    let input_idents = fn_inputs
24        .iter()
25        .map(|input| match input {
26            syn::FnArg::Typed(typed) => typed.pat.clone(),
27            syn::FnArg::Receiver(_) => panic!("`self` arguments are not supported"),
28        })
29        .collect::<Vec<_>>();
30
31    let gen = quote! {
32        #fn_vis #asyncness fn #fn_name(#fn_inputs) #fn_output {
33            let result = {
34                let start_time = Instant::now();
35                #asyncness fn inner(#fn_inputs) #fn_output #block
36                let res = inner(#(#input_idents),*)#awaitness;
37
38                METRICS
39                    .db
40                    .postgres
41                    .record(#label, start_time.elapsed().as_millis() as f64);
42                res
43            };
44            result
45        }
46    };
47
48    gen.into()
49}
50
51#[proc_macro_error]
52#[proc_macro_attribute]
53pub fn metrics(_attrs: TokenStream, input: TokenStream) -> TokenStream {
54    process_with_prometheus_metrics(input)
55}