bitwarden_logging_macro/
lib.rs1use proc_macro::TokenStream;
7use proc_macro2::TokenStream as TokenStream2;
8use quote::quote;
9use syn::{Meta, Token, parse::Parser, punctuated::Punctuated};
10
11const REJECT_MSG: &str = "`#[bitwarden_logging::instrument]` enforces `skip_all` by default. \
12 Use `fields(name = expr)` to opt in to logging specific arguments.";
13
14#[proc_macro_attribute]
24pub fn instrument(attr: TokenStream, item: TokenStream) -> TokenStream {
25 let item2: TokenStream2 = item.into();
26
27 let parser = Punctuated::<Meta, Token![,]>::parse_terminated;
28 let args = match parser.parse(attr) {
29 Ok(args) => args,
30 Err(e) => {
31 let err = e.to_compile_error();
32 return quote! { #err #item2 }.into();
33 }
34 };
35
36 let mut errors = TokenStream2::new();
37 for meta in &args {
38 let Some(last) = meta.path().segments.last() else {
39 continue;
40 };
41 if last.ident == "skip" || last.ident == "skip_all" {
42 errors.extend(syn::Error::new_spanned(meta, REJECT_MSG).to_compile_error());
43 }
44 }
45
46 if !errors.is_empty() {
47 return quote! { #errors #item2 }.into();
48 }
49
50 let args_iter = args.iter();
51 quote! {
52 #[allow(unknown_lints, tracing_instrument)]
56 #[::tracing::instrument(skip_all #(, #args_iter)*)]
57 #item2
58 }
59 .into()
60}