From f6b5602fa484ed18c200f69a6df0f475fcda4811 Mon Sep 17 00:00:00 2001 From: andylokandy Date: Wed, 19 Jun 2024 23:00:51 +0800 Subject: [PATCH] feat: log full function path --- Cargo.toml | 4 +- README.md | 12 +++--- examples/main.rs | 2 +- src/lib.rs | 78 +++++++++++++++++++------------------- tests/ui/ok/unreachable.rs | 4 +- 5 files changed, 52 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c108073..6f365f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "logcall" -version = "0.1.6" +version = "0.1.7" edition = "2021" authors = ["andylokandy "] description = "An attribute macro that logs the function return value." @@ -32,3 +32,5 @@ log = "0.4" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } env_logger = "0.10.0" async-trait = "0.1.70" +pollster = "0.3" +minitrace = "0.6" diff --git a/README.md b/README.md index 046f80f..cc2a1d4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ fn main() { multiply(2, 3); divide(2, 0).ok(); divide2(2, 0).ok(); - subtract(2, 3); + subtract(3, 2); } ``` @@ -82,11 +82,11 @@ fn main() { When the `main` function runs, it initializes the logger and logs each function call as specified: ```rust,ignore -[2024-06-16T12:41:04Z DEBUG main] add(a = 2, b = 3) => 5 -[2024-06-16T12:41:04Z INFO main] multiply(a = 2, b = 3) => 6 -[2024-06-16T12:41:04Z ERROR main] divide(a = 2, b = 0) => Err("Division by zero") -[2024-06-16T12:41:04Z ERROR main] divide2(a = 2, b = 0) => Err("Division by zero") -[2024-06-16T12:41:04Z DEBUG main] subtract(a = 2, ..) => -1 +[2024-06-19T15:01:23Z DEBUG main] main::add(a = 2, b = 3) => 5 +[2024-06-19T15:01:23Z INFO main] main::multiply(a = 2, b = 3) => 6 +[2024-06-19T15:01:23Z ERROR main] main::divide(a = 2, b = 0) => Err("Division by zero") +[2024-06-19T15:01:23Z ERROR main] main::divide2(a = 2, b = 0) => Err("Division by zero") +[2024-06-19T15:01:23Z DEBUG main] main::subtract(a = 3, ..) => 1 ``` ## Customization diff --git a/examples/main.rs b/examples/main.rs index d76e699..768ada4 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -47,5 +47,5 @@ fn main() { multiply(2, 3); divide(2, 0).ok(); divide2(2, 0).ok(); - subtract(2, 3); + subtract(3, 2); } diff --git a/src/lib.rs b/src/lib.rs index fb09ca1..4d5fa66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -172,8 +172,6 @@ fn gen_block( sig: &Signature, args: Args, ) -> proc_macro2::TokenStream { - let fn_name = sig.ident.to_string(); - match args { Args::Simple { level, @@ -183,31 +181,29 @@ fn gen_block( // If the function is an `async fn`, this will wrap it in an async block. if async_context { let input_format = input_format.unwrap_or_else(|| gen_input_format(sig)); - let log = gen_log(&level, &fn_name, "__input_string", "__ret_value"); + let log = gen_log(&level, "__input_string", "__ret_value"); let block = quote::quote_spanned!(block.span()=> - async move { - #[allow(unused_braces)] - #[allow(unknown_lints)] - #[allow(clippy::useless_format)] - let __input_string = format!(#input_format); - let __ret_value = async move { #block }.await; - #log; - __ret_value - } + #[allow(unknown_lints)] + #[allow(clippy::useless_format)] + let __input_string = format!(#input_format); + let __ret_value = #block; + #log; + __ret_value ); if async_keyword { + block + } else { quote::quote_spanned!(block.span()=> - #block.await + async move { + #block + } ) - } else { - block } } else { let input_format = input_format.unwrap_or_else(|| gen_input_format(sig)); - let log = gen_log(&level, &fn_name, "__input_string", "__ret_value"); + let log = gen_log(&level, "__input_string", "__ret_value"); quote::quote_spanned!(block.span()=> - #[allow(unused_braces)] #[allow(unknown_lints)] #[allow(clippy::useless_format)] let __input_string = format!(#input_format); @@ -225,7 +221,7 @@ fn gen_block( input_format, } => { let ok_arm = if let Some(ok_level) = ok_level { - let log_ok = gen_log(&ok_level, &fn_name, "__input_string", "__ret_value"); + let log_ok = gen_log(&ok_level, "__input_string", "__ret_value"); quote::quote_spanned!(block.span()=> __ret_value@Ok(_) => { #log_ok; @@ -238,7 +234,7 @@ fn gen_block( ) }; let err_arm = if let Some(err_level) = err_level { - let log_err = gen_log(&err_level, &fn_name, "__input_string", "__ret_value"); + let log_err = gen_log(&err_level, "__input_string", "__ret_value"); quote::quote_spanned!(block.span()=> __ret_value@Err(_) => { #log_err; @@ -256,25 +252,24 @@ fn gen_block( if async_context { let input_format = input_format.unwrap_or_else(|| gen_input_format(sig)); let block = quote::quote_spanned!(block.span()=> - async move { - #[allow(unknown_lints)] - #[allow(clippy::useless_format)] - let __input_string = format!(#input_format); - #[allow(unused_braces)] - let __ret_value = async move { #block }.await; - match __ret_value { - #ok_arm - #err_arm - } + #[allow(unknown_lints)] + #[allow(clippy::useless_format)] + let __input_string = format!(#input_format); + let __ret_value = #block; + match __ret_value { + #ok_arm + #err_arm } ); if async_keyword { + block + } else { quote::quote_spanned!(block.span()=> - #block.await + async move { + #block + } ) - } else { - block } } else { let input_format = input_format.unwrap_or_else(|| gen_input_format(sig)); @@ -282,7 +277,6 @@ fn gen_block( #[allow(unknown_lints)] #[allow(clippy::useless_format)] let __input_string = format!(#input_format); - #[allow(unused_braces)] #[allow(unknown_lints)] #[allow(clippy::redundant_closure_call)] let __ret_value = (move || #block)(); @@ -296,12 +290,7 @@ fn gen_block( } } -fn gen_log( - level: &str, - fn_name: &str, - input_string: &str, - return_value: &str, -) -> proc_macro2::TokenStream { +fn gen_log(level: &str, input_string: &str, return_value: &str) -> proc_macro2::TokenStream { let level = level.to_lowercase(); if !["error", "warn", "info", "debug", "trace"].contains(&level.as_str()) { abort_call_site!("unknown log level"); @@ -309,6 +298,17 @@ fn gen_log( let level: Ident = Ident::new(&level, Span::call_site()); let input_string: Ident = Ident::new(input_string, Span::call_site()); let return_value: Ident = Ident::new(return_value, Span::call_site()); + let fn_name = quote::quote! { + { + fn f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(f); + let name = &name[..name.len() - 3]; + name.trim_end_matches("::{{closure}}") + } + }; quote::quote!( log::#level! ("{}({}) => {:?}", #fn_name, #input_string, &#return_value) ) diff --git a/tests/ui/ok/unreachable.rs b/tests/ui/ok/unreachable.rs index c311896..684b548 100644 --- a/tests/ui/ok/unreachable.rs +++ b/tests/ui/ok/unreachable.rs @@ -1,10 +1,12 @@ +#![allow(unreachable_code)] + #[logcall::logcall("info")] async fn f(a: u32) -> u32 { if a == 1 { return 1; } - unreachable!() + unreachable!() } #[tokio::main]