mirror of
https://github.com/flibusta-apps/book_bot.git
synced 2026-03-02 22:55:24 +01:00
Add book_bot_macros proc-macro crate
Introduce log_handler attribute macro that injects tracing logs into handler functions. It extracts user_id from Message (optionally) or CallbackQuery and logs handler name; falls back to logging handler only.
This commit is contained in:
12
book_bot_macros/Cargo.toml
Normal file
12
book_bot_macros/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "book_bot_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = { workspace = true }
|
||||||
|
quote = { workspace = true }
|
||||||
|
proc-macro2 = { workspace = true }
|
||||||
75
book_bot_macros/src/lib.rs
Normal file
75
book_bot_macros/src/lib.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, FnArg, ItemFn, LitStr, Pat, PatType, Type, TypePath};
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn log_handler(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let handler_name = parse_macro_input!(attr as LitStr);
|
||||||
|
let input_fn = parse_macro_input!(item as ItemFn);
|
||||||
|
|
||||||
|
let fn_vis = &input_fn.vis;
|
||||||
|
let fn_sig = &input_fn.sig;
|
||||||
|
let fn_block = &input_fn.block;
|
||||||
|
let fn_attrs = &input_fn.attrs;
|
||||||
|
|
||||||
|
let log_stmt = generate_log_stmt(&input_fn, &handler_name);
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#(#fn_attrs)*
|
||||||
|
#fn_vis #fn_sig {
|
||||||
|
#log_stmt
|
||||||
|
#fn_block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_type_ident(ty: &Type) -> Option<String> {
|
||||||
|
if let Type::Path(TypePath { path, .. }) = ty {
|
||||||
|
path.segments.last().map(|s| s.ident.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_param_ident(fn_arg: &FnArg) -> Option<(proc_macro2::Ident, String)> {
|
||||||
|
if let FnArg::Typed(PatType { pat, ty, .. }) = fn_arg {
|
||||||
|
if let Pat::Ident(pat_ident) = pat.as_ref() {
|
||||||
|
if let Some(type_name) = get_type_ident(ty) {
|
||||||
|
return Some((pat_ident.ident.clone(), type_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_log_stmt(input_fn: &ItemFn, handler_name: &LitStr) -> proc_macro2::TokenStream {
|
||||||
|
for fn_arg in &input_fn.sig.inputs {
|
||||||
|
if let Some((ident, type_name)) = get_param_ident(fn_arg) {
|
||||||
|
match type_name.as_str() {
|
||||||
|
"Message" => {
|
||||||
|
return quote! {
|
||||||
|
tracing::info!(
|
||||||
|
handler = #handler_name,
|
||||||
|
user_id = ?#ident.from.as_ref().map(|u| u.id.0)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"CallbackQuery" => {
|
||||||
|
return quote! {
|
||||||
|
tracing::info!(
|
||||||
|
handler = #handler_name,
|
||||||
|
user_id = #ident.from.id.0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: log without user_id if no known type found
|
||||||
|
quote! {
|
||||||
|
tracing::info!(handler = #handler_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user