diff --git a/CHANGELOG.md b/CHANGELOG.md index fb62a2d3..c6f2f633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ## v0.6.1 -- Add macro attribute `#[trace(path_name = true)]` to use the full path of the function instead of only the function name. +- Macro will use the full path of the function as span name instead of the only function name. You can turn it off by setting `#[trace(short_name = true)]`. +- Add utility macros `func_name!()`, `full_name!()`, and `file_location!()` to generate names for use in span. ## v0.6.0 diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index 67c1bbef..0caace2d 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -24,8 +24,8 @@ struct Args { } enum Name { - Function(String), - FullPath, + Plain(String), + FullName, } impl Args { @@ -36,7 +36,7 @@ impl Args { let mut args = HashSet::new(); let mut func_name = func_name; - let mut path_name = false; + let mut short_name = false; let mut enter_on_poll = false; for arg in &input { @@ -53,9 +53,9 @@ impl Args { path, lit: Lit::Bool(b), .. - })) if path.is_ident("path_name") => { - path_name = b.value; - args.insert("path_name"); + })) if path.is_ident("short_name") => { + short_name = b.value; + args.insert("short_name"); } NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, @@ -69,13 +69,15 @@ impl Args { } } - let name = if path_name { - if args.contains("name") { - abort_call_site!("`name` and `path_name` can not be used together"); + let name = if args.contains("name") { + if short_name { + abort_call_site!("`name` and `short_name` can not be used together"); } - Name::FullPath + Name::Plain(func_name) + } else if short_name { + Name::Plain(func_name) } else { - Name::Function(func_name) + Name::FullName }; if args.len() != input.len() { @@ -99,9 +101,9 @@ impl Args { /// /// ## Arguments /// -/// * `name` - The name of the span. Defaults to the function name. -/// * `path_name` - Whether to use the full path of the function as the span name. Defaults to `false`. -/// * `enter_on_poll` - Whether to enter the span on poll, if set to `false`, `in_span` will be used. +/// * `name` - The name of the span. Defaults to the full path of the function. +/// * `short_name` - Whether to use the function name without path as the span name. Defaults to `false`. +/// * `enter_on_poll` - Whether to enter the span on poll. If set to `false`, `in_span` will be used. /// Only available for `async fn`. Defaults to `false`. /// /// # Examples @@ -131,7 +133,7 @@ impl Args { /// # use minitrace::prelude::*; /// # use minitrace::local::LocalSpan; /// fn foo() { -/// let __guard__ = LocalSpan::enter_with_local_parent("foo"); +/// let __guard__ = LocalSpan::enter_with_local_parent("example::foo"); /// // ... /// } /// @@ -139,7 +141,7 @@ impl Args { /// async { /// // ... /// } -/// .in_span(Span::enter_with_local_parent("bar")) +/// .in_span(Span::enter_with_local_parent("example::bar")) /// .await /// } /// @@ -278,19 +280,11 @@ fn gen_block( fn gen_name(span: proc_macro2::Span, name: Name) -> proc_macro2::TokenStream { match name { - Name::Function(func_name) => quote_spanned!(span=> - #func_name + Name::Plain(name) => quote_spanned!(span=> + #name ), - Name::FullPath => quote_spanned!(span=> - { - 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}}") - } + Name::FullName => quote_spanned!(span=> + minitrace::full_name!() ), } } diff --git a/minitrace-macro/tests/ui/err/has-name-and-path-name.stderr b/minitrace-macro/tests/ui/err/has-name-and-path-name.stderr deleted file mode 100644 index 74662dc2..00000000 --- a/minitrace-macro/tests/ui/err/has-name-and-path-name.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: `name` and `path_name` can not be used together - --> tests/ui/err/has-name-and-path-name.rs:3:1 - | -3 | #[trace(name = "Name", path_name = true)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `trace` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/minitrace-macro/tests/ui/err/has-name-and-path-name.rs b/minitrace-macro/tests/ui/err/has-name-and-short-name.rs similarity index 52% rename from minitrace-macro/tests/ui/err/has-name-and-path-name.rs rename to minitrace-macro/tests/ui/err/has-name-and-short-name.rs index 50edfe36..b804371b 100644 --- a/minitrace-macro/tests/ui/err/has-name-and-path-name.rs +++ b/minitrace-macro/tests/ui/err/has-name-and-short-name.rs @@ -1,6 +1,6 @@ use minitrace::trace; -#[trace(name = "Name", path_name = true)] +#[trace(name = "Name", short_name = true)] fn f() {} fn main() {} diff --git a/minitrace-macro/tests/ui/err/has-name-and-short-name.stderr b/minitrace-macro/tests/ui/err/has-name-and-short-name.stderr new file mode 100644 index 00000000..5c1dff5c --- /dev/null +++ b/minitrace-macro/tests/ui/err/has-name-and-short-name.stderr @@ -0,0 +1,7 @@ +error: `name` and `short_name` can not be used together + --> tests/ui/err/has-name-and-short-name.rs:3:1 + | +3 | #[trace(name = "Name", short_name = true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `trace` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/minitrace-macro/tests/ui/ok/has-name-and-path-name.rs b/minitrace-macro/tests/ui/ok/has-name-and-short-name.rs similarity index 71% rename from minitrace-macro/tests/ui/ok/has-name-and-path-name.rs rename to minitrace-macro/tests/ui/ok/has-name-and-short-name.rs index 7c17d5ac..03f1d0c5 100644 --- a/minitrace-macro/tests/ui/ok/has-name-and-path-name.rs +++ b/minitrace-macro/tests/ui/ok/has-name-and-short-name.rs @@ -1,6 +1,6 @@ use minitrace::trace; -#[trace(name = "Name", path_name = false)] +#[trace(name = "Name", short_name = false)] async fn f(a: u32) -> u32 { a } diff --git a/minitrace-macro/tests/ui/ok/has-path-name.rs b/minitrace-macro/tests/ui/ok/has-short-name.rs similarity index 79% rename from minitrace-macro/tests/ui/ok/has-path-name.rs rename to minitrace-macro/tests/ui/ok/has-short-name.rs index 61bf908e..67b0378f 100644 --- a/minitrace-macro/tests/ui/ok/has-path-name.rs +++ b/minitrace-macro/tests/ui/ok/has-short-name.rs @@ -1,6 +1,6 @@ use minitrace::trace; -#[trace(path_name = true)] +#[trace(short_name = true)] async fn f(a: u32) -> u32 { a } diff --git a/minitrace/src/lib.rs b/minitrace/src/lib.rs index cb9a51b1..4cf5e3ca 100644 --- a/minitrace/src/lib.rs +++ b/minitrace/src/lib.rs @@ -315,6 +315,7 @@ pub mod collector; mod event; pub mod future; pub mod local; +mod macros; mod span; #[doc(hidden)] pub mod util; diff --git a/minitrace/src/macros.rs b/minitrace/src/macros.rs new file mode 100644 index 00000000..37a221e2 --- /dev/null +++ b/minitrace/src/macros.rs @@ -0,0 +1,71 @@ +// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. + +/// Get the name of the function where the macro is invoked. Returns a `&'static str`. +/// +/// # Example +/// +/// ``` +/// use minitrace::func_name; +/// +/// fn foo() { +/// assert_eq!(func_name!(), "foo"); +/// } +/// # foo() +/// ``` +#[macro_export] +macro_rules! func_name { + () => {{ + 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.rsplit("::") + .find(|name| *name != "{{closure}}") + .unwrap() + }}; +} + +/// Get the full path of the function where the macro is invoked. Returns a `&'static str`. +/// +/// # Example +/// +/// ``` +/// use minitrace::full_name; +/// +/// fn foo() { +/// assert_eq!(full_name!(), "rust_out::main::_doctest_main_minitrace_src_macros_rs_34_0::foo"); +/// } +/// # foo() +#[macro_export] +macro_rules! full_name { + () => {{ + 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}}") + }}; +} + +/// Get the source file location where the macro is invoked. Returns a `&'static str`. +/// +/// # Example +/// +/// ``` +/// use minitrace::file_location; +/// +/// fn foo() { +/// assert_eq!(file_location!(), "minitrace/src/macros.rs:8:15"); +/// } +/// # #[cfg(not(target_os = "windows"))] +/// # foo() +#[macro_export] +macro_rules! file_location { + () => { + std::concat!(file!(), ":", line!(), ":", column!()) + }; +} diff --git a/minitrace/tests/lib.rs b/minitrace/tests/lib.rs index 77844bf7..eec0d179 100644 --- a/minitrace/tests/lib.rs +++ b/minitrace/tests/lib.rs @@ -390,7 +390,7 @@ fn test_macro() { } } - #[trace(enter_on_poll = true)] + #[trace(short_name = true, enter_on_poll = true)] async fn work(millis: &u64) { let _g = Span::enter_with_local_parent("work-inner"); tokio::time::sleep(std::time::Duration::from_millis(*millis)) @@ -399,7 +399,7 @@ fn test_macro() { } impl Bar { - #[trace] + #[trace(short_name = true)] async fn work2(&self, millis: &u64) { let _g = Span::enter_with_local_parent("work-inner"); tokio::time::sleep(std::time::Duration::from_millis(*millis)) @@ -408,7 +408,7 @@ fn test_macro() { } } - #[trace] + #[trace(short_name = true)] async fn work3<'a>(millis1: &'a u64, millis2: &u64) { let _g = Span::enter_with_local_parent("work-inner"); tokio::time::sleep(std::time::Duration::from_millis(*millis1)) @@ -476,23 +476,23 @@ root [] #[test] #[serial] fn macro_example() { - #[trace] - fn do_something(i: u64) { + #[trace(short_name = true)] + fn do_something_short_name(i: u64) { std::thread::sleep(std::time::Duration::from_millis(i)); } - #[trace] - async fn do_something_async(i: u64) { + #[trace(short_name = true)] + async fn do_something_async_short_name(i: u64) { futures_timer::Delay::new(std::time::Duration::from_millis(i)).await; } - #[trace(path_name = true)] - fn do_something_path_name(i: u64) { + #[trace] + fn do_something(i: u64) { std::thread::sleep(std::time::Duration::from_millis(i)); } - #[trace(path_name = true)] - async fn do_something_async_path_name(i: u64) { + #[trace] + async fn do_something_async(i: u64) { futures_timer::Delay::new(std::time::Duration::from_millis(i)).await; } @@ -504,18 +504,18 @@ fn macro_example() { let _g = root.set_local_parent(); do_something(100); block_on(do_something_async(100)); - do_something_path_name(100); - block_on(do_something_async_path_name(100)); + do_something_short_name(100); + block_on(do_something_async_short_name(100)); } minitrace::flush(); let expected_graph = r#" root [] - do_something [] - do_something_async [] - lib::macro_example::{{closure}}::do_something_async_path_name [] - lib::macro_example::{{closure}}::do_something_path_name [] + do_something_async_short_name [] + do_something_short_name [] + lib::macro_example::{{closure}}::do_something [] + lib::macro_example::{{closure}}::do_something_async [] "#; assert_eq!( tree_str_from_span_records(collected_spans.lock().clone()), @@ -589,7 +589,7 @@ root [] #[test] #[serial] fn max_spans_per_trace() { - #[trace] + #[trace(short_name = true)] fn recursive(n: usize) { if n > 1 { recursive(n - 1);