From df1556761cbdfe709e4b00ca36aad95e2c1adc02 Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:38:52 +0800 Subject: [PATCH 1/7] feat: add properties to #[trace] Signed-off-by: Andy Lok --- CHANGELOG.md | 1 + minitrace-macro/src/lib.rs | 261 ++++++++++++------ .../ui/err/has-duplicated-arguments.stderr | 8 +- .../tests/ui/err/has-empty-name.rs | 6 + .../tests/ui/err/has-empty-name.stderr | 7 + .../tests/ui/err/has-expr-argument.stderr | 8 +- .../tests/ui/err/has-ident-arguments.stderr | 8 +- .../err/has-properties-and-enter-on-poll.rs | 6 + .../has-properties-and-enter-on-poll.stderr | 7 + .../ui/err/item-is-not-a-function.stderr | 8 +- ...ame-is-not-an-assignment-expression.stderr | 8 +- .../tests/ui/err/properties-non-string.rs | 6 + .../tests/ui/err/properties-non-string.stderr | 5 + .../tests/ui/err/properties-partial-escape.rs | 6 + .../ui/err/properties-partial-escape.stderr | 8 + .../tests/ui/err/trace-interleaved.stderr | 8 +- minitrace-macro/tests/ui/ok/has-properties.rs | 21 ++ minitrace/examples/asynchronous.rs | 2 +- minitrace/examples/synchronous.rs | 2 +- minitrace/src/local/local_collector.rs | 6 +- minitrace/src/local/local_span.rs | 37 ++- minitrace/src/local/local_span_line.rs | 10 +- minitrace/src/local/local_span_stack.rs | 8 +- minitrace/src/local/span_queue.rs | 15 +- minitrace/src/span.rs | 37 ++- minitrace/src/util/tree.rs | 1 - minitrace/tests/lib.rs | 66 ++++- test-statically-disable/src/main.rs | 8 +- 28 files changed, 394 insertions(+), 180 deletions(-) create mode 100644 minitrace-macro/tests/ui/err/has-empty-name.rs create mode 100644 minitrace-macro/tests/ui/err/has-empty-name.stderr create mode 100644 minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.rs create mode 100644 minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.stderr create mode 100644 minitrace-macro/tests/ui/err/properties-non-string.rs create mode 100644 minitrace-macro/tests/ui/err/properties-non-string.stderr create mode 100644 minitrace-macro/tests/ui/err/properties-partial-escape.rs create mode 100644 minitrace-macro/tests/ui/err/properties-partial-escape.stderr create mode 100644 minitrace-macro/tests/ui/ok/has-properties.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index b5ff0197..e168f1b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Add `LocalSpans::to_span_records()`. +- Add `#[trace(properties = { "k1": "v1", "k2": "v2" })]`. ## v0.6.2 diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index adf3d65b..6754a617 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -12,82 +12,96 @@ extern crate proc_macro; #[macro_use] extern crate proc_macro_error; -use std::collections::HashSet; +use std::collections::HashMap; +use proc_macro2::Span; use quote::quote_spanned; +use syn::parse::Parse; +use syn::parse::ParseStream; +use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::*; struct Args { - name: Name, + name: Option, + short_name: bool, enter_on_poll: bool, + properties: Vec<(String, String)>, } -enum Name { - Plain(String), - FullName, +struct Property { + key: String, + value: String, } -impl Args { - fn parse(func_name: String, input: AttributeArgs) -> Args { - if input.len() > 2 { - abort_call_site!("too many arguments"); - } +impl Parse for Property { + fn parse(input: ParseStream) -> Result { + let key: LitStr = input.parse()?; + input.parse::()?; + let value: LitStr = input.parse()?; + Ok(Property { + key: key.value(), + value: value.value(), + }) + } +} - let mut args = HashSet::new(); - let mut func_name = func_name; +impl Parse for Args { + fn parse(input: ParseStream) -> Result { + let mut name = None; let mut short_name = false; let mut enter_on_poll = false; + let mut properties = Vec::new(); + let mut seen = HashMap::new(); - for arg in &input { - match arg { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, - lit: Lit::Str(s), - .. - })) if path.is_ident("name") => { - func_name = s.value(); - args.insert("name"); + while !input.is_empty() { + let ident: Ident = input.parse()?; + if seen.contains_key(&ident.to_string()) { + return Err(syn::Error::new(ident.span(), "duplicate argument")); + } + seen.insert(ident.to_string(), ()); + input.parse::()?; + match ident.to_string().as_str() { + "name" => { + let parsed_name: LitStr = input.parse()?; + name = Some(parsed_name.value()); } - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, - lit: Lit::Bool(b), - .. - })) if path.is_ident("short_name") => { - short_name = b.value; - args.insert("short_name"); + "short_name" => { + let parsed_short_name: LitBool = input.parse()?; + short_name = parsed_short_name.value; } - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, - lit: Lit::Bool(b), - .. - })) if path.is_ident("enter_on_poll") => { - enter_on_poll = b.value; - args.insert("enter_on_poll"); + "enter_on_poll" => { + let parsed_enter_on_poll: LitBool = input.parse()?; + enter_on_poll = parsed_enter_on_poll.value; } - _ => abort_call_site!("invalid argument"), + "properties" => { + let content; + let _brace_token = syn::braced!(content in input); + let property_list: Punctuated = + content.parse_terminated(Property::parse)?; + for property in property_list { + if properties.iter().any(|(k, _)| k == &property.key) { + return Err(syn::Error::new( + Span::call_site(), + "duplicate property key", + )); + } + properties.push((property.key, property.value)); + } + } + _ => return Err(syn::Error::new(Span::call_site(), "unexpected identifier")), } - } - - let name = if args.contains("name") { - if short_name { - abort_call_site!("`name` and `short_name` can not be used together"); + if !input.is_empty() { + let _ = input.parse::(); } - Name::Plain(func_name) - } else if short_name { - Name::Plain(func_name) - } else { - Name::FullName - }; - - if args.len() != input.len() { - abort_call_site!("duplicated arguments"); } - Args { + Ok(Args { name, + short_name, enter_on_poll, - } + properties, + }) } } @@ -106,6 +120,8 @@ impl Args { /// * `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`. +/// * `properties` - A list of key-value pairs to be added as properties to the span. The value can be +/// a format string, where the function arguments are accessible. Defaults to `{}`. /// /// # Examples /// @@ -113,12 +129,12 @@ impl Args { /// use minitrace::prelude::*; /// /// #[trace] -/// fn foo() { +/// fn simple() { /// // ... /// } /// -/// #[trace] -/// async fn bar() { +/// #[trace(short_name = true)] +/// async fn simple_async() { /// // ... /// } /// @@ -126,6 +142,11 @@ impl Args { /// async fn baz() { /// // ... /// } +/// +/// #[trace(properties = { "k1": "v1", "a": "argument `a` is {a:?}" })] +/// async fn properties(a: u64) { +/// // ... +/// } /// ``` /// /// The code snippets above are equivalent to: @@ -133,16 +154,17 @@ impl Args { /// ``` /// # use minitrace::prelude::*; /// # use minitrace::local::LocalSpan; -/// fn foo() { -/// let __guard__ = LocalSpan::enter_with_local_parent("example::foo"); +/// fn simple() { +/// let __guard__ = LocalSpan::enter_with_local_parent("example::simple"); /// // ... /// } /// -/// async fn bar() { +/// async fn simple_async() { +/// let __span__ = Span::enter_with_local_parent("simple_async"); /// async { /// // ... /// } -/// .in_span(Span::enter_with_local_parent("example::bar")) +/// .in_span(__span__) /// .await /// } /// @@ -153,6 +175,19 @@ impl Args { /// .enter_on_poll("qux") /// .await /// } +/// +/// async fn properties(a: u64) { +/// let __span__ = Span::enter_with_local_parent("example::properties") +/// .with_properties(|| [ +/// ("k1".into(), "v1".into()), +/// ("a".into(), format!("argument `a` is {a:?}").into()) +/// ]); +/// async { +/// // ... +/// } +/// .in_span(__span__) +/// .await +/// } /// ``` #[proc_macro_attribute] #[proc_macro_error] @@ -160,12 +195,10 @@ pub fn trace( args: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { + let args = parse_macro_input!(args as Args); let input = syn::parse_macro_input!(item as ItemFn); - let args = Args::parse( - input.sig.ident.to_string(), - syn::parse_macro_input!(args as AttributeArgs), - ); + let func_name = input.sig.ident.to_string(); // check for async_trait-like patterns in the block, and instrument // the future instead of the wrapper let func_body = if let Some(internal_fun) = @@ -183,7 +216,8 @@ pub fn trace( AsyncTraitKind::Async(async_expr) => { // fallback if we couldn't find the '__async_trait' binding, might be // useful for crates exhibiting the same behaviors as async-trait - let instrumented_block = gen_block(&async_expr.block, true, false, args); + let instrumented_block = + gen_block(&func_name, &async_expr.block, true, false, &args); let async_attrs = &async_expr.attrs; quote::quote! { Box::pin(#(#async_attrs) * #instrumented_block) @@ -192,10 +226,11 @@ pub fn trace( } } else { gen_block( + &func_name, &input.block, input.sig.asyncness.is_some(), input.sig.asyncness.is_some(), - args, + &args, ) }; @@ -231,14 +266,82 @@ pub fn trace( .into() } +fn gen_name(span: proc_macro2::Span, func_name: &str, args: &Args) -> proc_macro2::TokenStream { + match &args.name { + Some(name) if name.is_empty() => { + abort_call_site!("`name` can not be empty") + } + Some(_) if args.short_name => { + abort_call_site!("`name` and `short_name` can not be used together") + } + Some(name) => { + quote_spanned!(span=> + #name + ) + } + None if args.short_name => { + quote_spanned!(span=> + #func_name + ) + } + None => { + quote_spanned!(span=> + minitrace::full_name!() + ) + } + } +} + +fn gen_properties(span: proc_macro2::Span, args: &Args) -> proc_macro2::TokenStream { + if args.properties.is_empty() { + return quote!(); + } + + if args.enter_on_poll { + abort_call_site!("`enter_on_poll` can not be used with `properties`") + } + + let properties = args.properties.iter().map(|(k, v)| { + let k = k.as_str(); + let v = v.as_str(); + + let (v, need_format) = unescape_format_string(v); + + if need_format { + quote_spanned!(span=> + (#k.into(), format!(#v).into()) + ) + } else { + quote_spanned!(span=> + (#k.into(), #v.into()) + ) + } + }); + let properties = Punctuated::<_, Token![,]>::from_iter(properties); + quote_spanned!(span=> #properties) +} + +fn unescape_format_string(s: &str) -> (String, bool) { + let unescaped_delete = s.replace("{{", "").replace("}}", ""); + let contains_valid_format_string = unescaped_delete.contains("{") || unescaped_delete.contains("}"); + if contains_valid_format_string { + return (s.to_string(), true); + } else { + let unescaped_replace = s.replace("{{", "{").replace("}}", "}"); + return (unescaped_replace, false); + } +} + /// Instrument a block fn gen_block( + func_name: &str, block: &Block, async_context: bool, async_keyword: bool, - args: Args, + args: &Args, ) -> proc_macro2::TokenStream { - let name = gen_name(block.span(), args.name); + let name = gen_name(block.span(), func_name, args); + let properties = gen_properties(block.span(), args); // Generate the instrumented function body. // If the function is an `async fn`, this will wrap it in an async block. @@ -253,10 +356,13 @@ fn gen_block( ) } else { quote_spanned!(block.span()=> - minitrace::future::FutureExt::in_span( - async move { #block }, - minitrace::Span::enter_with_local_parent( #name ) - ) + { + let __span__ = minitrace::Span::enter_with_local_parent( #name ).with_properties(|| [#properties]); + minitrace::future::FutureExt::in_span( + async move { #block }, + __span__, + ) + } ) }; @@ -273,23 +379,12 @@ fn gen_block( } quote_spanned!(block.span()=> - let __guard = minitrace::local::LocalSpan::enter_with_local_parent( #name ); + let __guard__ = minitrace::local::LocalSpan::enter_with_local_parent( #name ).with_properties(|| [#properties]); #block ) } } -fn gen_name(span: proc_macro2::Span, name: Name) -> proc_macro2::TokenStream { - match name { - Name::Plain(name) => quote_spanned!(span=> - #name - ), - Name::FullName => quote_spanned!(span=> - minitrace::full_name!() - ), - } -} - enum AsyncTraitKind<'a> { // old construction. Contains the function Function, diff --git a/minitrace-macro/tests/ui/err/has-duplicated-arguments.stderr b/minitrace-macro/tests/ui/err/has-duplicated-arguments.stderr index a1c2a7a0..8ead9ef5 100644 --- a/minitrace-macro/tests/ui/err/has-duplicated-arguments.stderr +++ b/minitrace-macro/tests/ui/err/has-duplicated-arguments.stderr @@ -1,7 +1,5 @@ -error: duplicated arguments - --> tests/ui/err/has-duplicated-arguments.rs:3:1 +error: duplicate argument + --> tests/ui/err/has-duplicated-arguments.rs:3:24 | 3 | #[trace(name = "Name", name = "Name")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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-empty-name.rs b/minitrace-macro/tests/ui/err/has-empty-name.rs new file mode 100644 index 00000000..513797bb --- /dev/null +++ b/minitrace-macro/tests/ui/err/has-empty-name.rs @@ -0,0 +1,6 @@ +use minitrace::trace; + +#[trace(name = "")] +fn f() {} + +fn main() {} diff --git a/minitrace-macro/tests/ui/err/has-empty-name.stderr b/minitrace-macro/tests/ui/err/has-empty-name.stderr new file mode 100644 index 00000000..a0740806 --- /dev/null +++ b/minitrace-macro/tests/ui/err/has-empty-name.stderr @@ -0,0 +1,7 @@ +error: `name` can not be empty + --> tests/ui/err/has-empty-name.rs:3:1 + | +3 | #[trace(name = "")] + | ^^^^^^^^^^^^^^^^^^^ + | + = 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-expr-argument.stderr b/minitrace-macro/tests/ui/err/has-expr-argument.stderr index b6acfa11..5b56bba3 100644 --- a/minitrace-macro/tests/ui/err/has-expr-argument.stderr +++ b/minitrace-macro/tests/ui/err/has-expr-argument.stderr @@ -1,7 +1,5 @@ -error: invalid argument - --> tests/ui/err/has-expr-argument.rs:3:1 +error: expected identifier + --> tests/ui/err/has-expr-argument.rs:3:9 | 3 | #[trace(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-ident-arguments.stderr b/minitrace-macro/tests/ui/err/has-ident-arguments.stderr index dec9fb1c..c7fa9c2c 100644 --- a/minitrace-macro/tests/ui/err/has-ident-arguments.stderr +++ b/minitrace-macro/tests/ui/err/has-ident-arguments.stderr @@ -1,7 +1,5 @@ -error: invalid argument - --> tests/ui/err/has-ident-arguments.rs:3:1 +error: expected `=` + --> tests/ui/err/has-ident-arguments.rs:3:10 | 3 | #[trace(a, b)] - | ^^^^^^^^^^^^^^ - | - = 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-properties-and-enter-on-poll.rs b/minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.rs new file mode 100644 index 00000000..279e23d6 --- /dev/null +++ b/minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.rs @@ -0,0 +1,6 @@ +use minitrace::trace; + +#[trace(enter_on_poll = true, properties = { "a": "b" })] +fn f() {} + +fn main() {} diff --git a/minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.stderr b/minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.stderr new file mode 100644 index 00000000..2caf0da4 --- /dev/null +++ b/minitrace-macro/tests/ui/err/has-properties-and-enter-on-poll.stderr @@ -0,0 +1,7 @@ +error: `enter_on_poll` can not be used with `properties` + --> tests/ui/err/has-properties-and-enter-on-poll.rs:3:1 + | +3 | #[trace(enter_on_poll = true, properties = { "a": "b" })] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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/item-is-not-a-function.stderr b/minitrace-macro/tests/ui/err/item-is-not-a-function.stderr index 226dd70b..14425104 100644 --- a/minitrace-macro/tests/ui/err/item-is-not-a-function.stderr +++ b/minitrace-macro/tests/ui/err/item-is-not-a-function.stderr @@ -1,5 +1,5 @@ -error: expected `fn` - --> tests/ui/err/item-is-not-a-function.rs:4:1 +error: expected identifier + --> tests/ui/err/item-is-not-a-function.rs:3:9 | -4 | struct S; - | ^^^^^^ +3 | #[trace("test-span")] + | ^^^^^^^^^^^ diff --git a/minitrace-macro/tests/ui/err/name-is-not-an-assignment-expression.stderr b/minitrace-macro/tests/ui/err/name-is-not-an-assignment-expression.stderr index 22e498e4..74b03d96 100644 --- a/minitrace-macro/tests/ui/err/name-is-not-an-assignment-expression.stderr +++ b/minitrace-macro/tests/ui/err/name-is-not-an-assignment-expression.stderr @@ -1,7 +1,5 @@ -error: invalid argument - --> tests/ui/err/name-is-not-an-assignment-expression.rs:3:1 +error: expected identifier + --> tests/ui/err/name-is-not-an-assignment-expression.rs:3:9 | 3 | #[trace("b")] - | ^^^^^^^^^^^^^ - | - = 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/properties-non-string.rs b/minitrace-macro/tests/ui/err/properties-non-string.rs new file mode 100644 index 00000000..4feea6ea --- /dev/null +++ b/minitrace-macro/tests/ui/err/properties-non-string.rs @@ -0,0 +1,6 @@ +use minitrace::trace; + +#[trace(properties = { a: "b" })] +fn f() {} + +fn main() {} diff --git a/minitrace-macro/tests/ui/err/properties-non-string.stderr b/minitrace-macro/tests/ui/err/properties-non-string.stderr new file mode 100644 index 00000000..0dd2becc --- /dev/null +++ b/minitrace-macro/tests/ui/err/properties-non-string.stderr @@ -0,0 +1,5 @@ +error: expected string literal + --> tests/ui/err/properties-non-string.rs:3:24 + | +3 | #[trace(properties = { a: "b" })] + | ^ diff --git a/minitrace-macro/tests/ui/err/properties-partial-escape.rs b/minitrace-macro/tests/ui/err/properties-partial-escape.rs new file mode 100644 index 00000000..7ab5d905 --- /dev/null +++ b/minitrace-macro/tests/ui/err/properties-partial-escape.rs @@ -0,0 +1,6 @@ +use minitrace::trace; + +#[trace(properties = { "a": "{{b}" })] +fn f(b: u8) {} + +fn main() {} diff --git a/minitrace-macro/tests/ui/err/properties-partial-escape.stderr b/minitrace-macro/tests/ui/err/properties-partial-escape.stderr new file mode 100644 index 00000000..5d0edbbc --- /dev/null +++ b/minitrace-macro/tests/ui/err/properties-partial-escape.stderr @@ -0,0 +1,8 @@ +error: invalid format string: unmatched `}` found + --> tests/ui/err/properties-partial-escape.rs:3:1 + | +3 | #[trace(properties = { "a": "{{b}" })] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + = 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/trace-interleaved.stderr b/minitrace-macro/tests/ui/err/trace-interleaved.stderr index 9107b500..76551cba 100644 --- a/minitrace-macro/tests/ui/err/trace-interleaved.stderr +++ b/minitrace-macro/tests/ui/err/trace-interleaved.stderr @@ -1,7 +1,5 @@ -error: invalid argument - --> tests/ui/err/trace-interleaved.rs:4:1 +error: expected identifier + --> tests/ui/err/trace-interleaved.rs:4:9 | 4 | #[trace(struct)] - | ^^^^^^^^^^^^^^^^ - | - = 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-properties.rs b/minitrace-macro/tests/ui/ok/has-properties.rs new file mode 100644 index 00000000..0a6197d2 --- /dev/null +++ b/minitrace-macro/tests/ui/ok/has-properties.rs @@ -0,0 +1,21 @@ +use minitrace::trace; + +#[trace(short_name = true, properties = { "k1": "v1", "a": "argument a is {a:?}", "b": "{b:?}", "escaped1": "{c:?}{{}}", "escaped2": "{{ \"a\": \"b\"}}" })] +async fn f(a: i64, b: &Bar, c: Bar) -> i64 { + drop(c); + a +} + +#[derive(Debug)] +struct Bar; + +#[trace(short_name = true, properties = {})] +async fn g(a: u32) -> u32 { + a +} + +#[tokio::main] +async fn main() { + f(1, &Bar, Bar).await; + g(1).await; +} diff --git a/minitrace/examples/asynchronous.rs b/minitrace/examples/asynchronous.rs index ecca53f2..aeb12d0d 100644 --- a/minitrace/examples/asynchronous.rs +++ b/minitrace/examples/asynchronous.rs @@ -47,7 +47,7 @@ async fn main() { let f = async { let jhs = { let _span = LocalSpan::enter_with_local_parent("a span") - .with_property(|| ("a property", "a value")); + .with_property(|| ("a property".into(), "a value".into())); parallel_job() }; diff --git a/minitrace/examples/synchronous.rs b/minitrace/examples/synchronous.rs index 2650d690..44b620db 100644 --- a/minitrace/examples/synchronous.rs +++ b/minitrace/examples/synchronous.rs @@ -31,7 +31,7 @@ async fn main() { let _g = root.set_local_parent(); let _span = LocalSpan::enter_with_local_parent("a span") - .with_property(|| ("a property", "a value")); + .with_property(|| ("a property".into(), "a value".into())); for i in 1..=10 { func1(i); diff --git a/minitrace/src/local/local_collector.rs b/minitrace/src/local/local_collector.rs index a16e7075..c0e8456c 100644 --- a/minitrace/src/local/local_collector.rs +++ b/minitrace/src/local/local_collector.rs @@ -316,8 +316,10 @@ span1 [] #[test] fn local_spans_to_span_record() { let collector = LocalCollector::start(); - let span1 = LocalSpan::enter_with_local_parent("span1").with_property(|| ("k1", "v1")); - let span2 = LocalSpan::enter_with_local_parent("span2").with_property(|| ("k2", "v2")); + let span1 = LocalSpan::enter_with_local_parent("span1") + .with_property(|| ("k1".into(), "v1".into())); + let span2 = LocalSpan::enter_with_local_parent("span2") + .with_property(|| ("k2".into(), "v2".into())); drop(span2); drop(span1); diff --git a/minitrace/src/local/local_span.rs b/minitrace/src/local/local_span.rs index 466cab3a..d797d754 100644 --- a/minitrace/src/local/local_span.rs +++ b/minitrace/src/local/local_span.rs @@ -63,16 +63,12 @@ impl LocalSpan { /// ``` /// use minitrace::prelude::*; /// - /// let span = - /// LocalSpan::enter_with_local_parent("a child span").with_property(|| ("key", "value")); + /// let span = LocalSpan::enter_with_local_parent("a child span") + /// .with_property(|| ("key".into(), "value".into())); /// ``` #[inline] - pub fn with_property(self, property: F) -> Self - where - K: Into>, - V: Into>, - F: FnOnce() -> (K, V), - { + pub fn with_property(self, property: F) -> Self + where F: FnOnce() -> (Cow<'static, str>, Cow<'static, str>) { self.with_properties(|| [property()]) } @@ -83,15 +79,17 @@ impl LocalSpan { /// ``` /// use minitrace::prelude::*; /// - /// let span = LocalSpan::enter_with_local_parent("a child span") - /// .with_properties(|| [("key1", "value1"), ("key2", "value2")]); + /// let span = LocalSpan::enter_with_local_parent("a child span").with_properties(|| { + /// [ + /// ("key1".into(), "value1".into()), + /// ("key2".into(), "value2".into()), + /// ] + /// }); /// ``` #[inline] - pub fn with_properties(self, properties: F) -> Self + pub fn with_properties(self, properties: F) -> Self where - K: Into>, - V: Into>, - I: IntoIterator, + I: IntoIterator, Cow<'static, str>)>, F: FnOnce() -> I, { #[cfg(feature = "enable")] @@ -161,8 +159,8 @@ mod tests { { let _g = LocalSpan::enter_with_stack("span1", stack.clone()); { - let _span = - LocalSpan::enter_with_stack("span2", stack).with_property(|| ("k1", "v1")); + let _span = LocalSpan::enter_with_stack("span2", stack) + .with_property(|| ("k1".into(), "v1".into())); } } @@ -179,7 +177,8 @@ span1 [] #[test] fn local_span_noop() { - let _span1 = LocalSpan::enter_with_local_parent("span1").with_property(|| ("k1", "v1")); + let _span1 = LocalSpan::enter_with_local_parent("span1") + .with_property(|| ("k1".into(), "v1".into())); } #[test] @@ -198,8 +197,8 @@ span1 [] { let span1 = LocalSpan::enter_with_stack("span1", stack.clone()); { - let _span2 = - LocalSpan::enter_with_stack("span2", stack).with_property(|| ("k1", "v1")); + let _span2 = LocalSpan::enter_with_stack("span2", stack) + .with_property(|| ("k1".into(), "v1".into())); drop(span1); } diff --git a/minitrace/src/local/local_span_line.rs b/minitrace/src/local/local_span_line.rs index b7dea471..7743cfc8 100644 --- a/minitrace/src/local/local_span_line.rs +++ b/minitrace/src/local/local_span_line.rs @@ -57,11 +57,9 @@ impl SpanLine { } #[inline] - pub fn add_properties(&mut self, handle: &LocalSpanHandle, properties: F) + pub fn add_properties(&mut self, handle: &LocalSpanHandle, properties: F) where - K: Into>, - V: Into>, - I: IntoIterator, + I: IntoIterator, Cow<'static, str>)>, F: FnOnce() -> I, { if self.epoch == handle.span_line_epoch { @@ -113,7 +111,7 @@ mod tests { let span2 = span_line.start_span("span2").unwrap(); { let span3 = span_line.start_span("span3").unwrap(); - span_line.add_properties(&span3, || [("k1", "v1")]); + span_line.add_properties(&span3, || [("k1".into(), "v1".into())]); span_line.finish_span(span3); } span_line.finish_span(span2); @@ -192,7 +190,7 @@ span [] assert_eq!(span_line2.span_line_epoch(), 2); let span = span_line1.start_span("span").unwrap(); - span_line2.add_properties(&span, || [("k1", "v1")]); + span_line2.add_properties(&span, || [("k1".into(), "v1".into())]); span_line1.finish_span(span); let raw_spans = span_line1.collect(1).unwrap().0.into_inner(); diff --git a/minitrace/src/local/local_span_stack.rs b/minitrace/src/local/local_span_stack.rs index 50c52d3e..72967a97 100644 --- a/minitrace/src/local/local_span_stack.rs +++ b/minitrace/src/local/local_span_stack.rs @@ -98,11 +98,9 @@ impl LocalSpanStack { } #[inline] - pub fn add_properties(&mut self, local_span_handle: &LocalSpanHandle, properties: F) + pub fn add_properties(&mut self, local_span_handle: &LocalSpanHandle, properties: F) where - K: Into>, - V: Into>, - I: IntoIterator, + I: IntoIterator, Cow<'static, str>)>, F: FnOnce() -> I, { debug_assert!(self.current_span_line().is_some()); @@ -357,7 +355,7 @@ span1 [] .into(), )) .unwrap(); - span_stack.add_properties(&span1, || [("k1", "v1")]); + span_stack.add_properties(&span1, || [("k1".into(), "v1".into())]); let _ = span_stack.unregister_and_collect(span_line2).unwrap(); } span_stack.exit_span(span1); diff --git a/minitrace/src/local/span_queue.rs b/minitrace/src/local/span_queue.rs index f168fe8c..8630f529 100644 --- a/minitrace/src/local/span_queue.rs +++ b/minitrace/src/local/span_queue.rs @@ -85,12 +85,8 @@ impl SpanQueue { } #[inline] - pub fn add_properties(&mut self, span_handle: &SpanHandle, properties: I) - where - K: Into>, - V: Into>, - I: IntoIterator, - { + pub fn add_properties(&mut self, span_handle: &SpanHandle, properties: I) + where I: IntoIterator, Cow<'static, str>)> { debug_assert!(span_handle.index < self.span_queue.len()); let span = &mut self.span_queue[span_handle.index]; @@ -149,10 +145,13 @@ span1 [] let mut queue = SpanQueue::with_capacity(16); { let span1 = queue.start_span("span1").unwrap(); - queue.add_properties(&span1, [("k1", "v1"), ("k2", "v2")]); + queue.add_properties(&span1, [ + ("k1".into(), "v1".into()), + ("k2".into(), "v2".into()), + ]); { let span2 = queue.start_span("span2").unwrap(); - queue.add_properties(&span2, [("k1", "v1")]); + queue.add_properties(&span2, [("k1".into(), "v1".into())]); queue.finish_span(span2); } queue.finish_span(span1); diff --git a/minitrace/src/span.rs b/minitrace/src/span.rs index 08529a73..7998b792 100644 --- a/minitrace/src/span.rs +++ b/minitrace/src/span.rs @@ -250,15 +250,12 @@ impl Span { /// ``` /// use minitrace::prelude::*; /// - /// let root = Span::root("root", SpanContext::random()).with_property(|| ("key", "value")); + /// let root = + /// Span::root("root", SpanContext::random()).with_property(|| ("key".into(), "value".into())); /// ``` #[inline] - pub fn with_property(self, property: F) -> Self - where - K: Into>, - V: Into>, - F: FnOnce() -> (K, V), - { + pub fn with_property(self, property: F) -> Self + where F: FnOnce() -> (Cow<'static, str>, Cow<'static, str>) { self.with_properties(move || [property()]) } @@ -269,15 +266,17 @@ impl Span { /// ``` /// use minitrace::prelude::*; /// - /// let root = Span::root("root", SpanContext::random()) - /// .with_properties(|| [("key1", "value1"), ("key2", "value2")]); + /// let root = Span::root("root", SpanContext::random()).with_properties(|| { + /// [ + /// ("key1".into(), "value1".into()), + /// ("key2".into(), "value2".into()), + /// ] + /// }); /// ``` #[inline] - pub fn with_properties(mut self, properties: F) -> Self + pub fn with_properties(mut self, properties: F) -> Self where - K: Into>, - V: Into>, - I: IntoIterator, + I: IntoIterator, Cow<'static, str>)>, F: FnOnce() -> I, { #[cfg(feature = "enable")] @@ -432,11 +431,9 @@ impl Span { #[cfg(feature = "enable")] impl SpanInner { #[inline] - fn add_properties(&mut self, properties: F) + fn add_properties(&mut self, properties: F) where - K: Into>, - V: Into>, - I: IntoIterator, + I: IntoIterator, Cow<'static, str>)>, F: FnOnce() -> I, { self.raw_span @@ -643,8 +640,8 @@ mod tests { let routine = |collect| { let parent_ctx = SpanContext::random(); let root = Span::root("root", parent_ctx, collect); - let child1 = - Span::enter_with_parent("child1", &root).with_properties(|| [("k1", "v1")]); + let child1 = Span::enter_with_parent("child1", &root) + .with_properties(|| [("k1".into(), "v1".into())]); let grandchild = Span::enter_with_parent("grandchild", &child1); let child2 = Span::enter_with_parent("child2", &root); @@ -712,7 +709,7 @@ root [] [&parent1, &parent2, &parent3, &parent4, &parent5, &child1], collect, ) - .with_property(|| ("k1", "v1")); + .with_property(|| ("k1".into(), "v1".into())); crossbeam::scope(move |scope| { let mut rng = thread_rng(); diff --git a/minitrace/src/util/tree.rs b/minitrace/src/util/tree.rs index bea78b2f..232a6659 100644 --- a/minitrace/src/util/tree.rs +++ b/minitrace/src/util/tree.rs @@ -58,7 +58,6 @@ impl Tree { child.sort(); } self.children.as_mut_slice().sort_unstable(); - self.properties.as_mut_slice().sort_unstable(); } pub fn from_raw_spans(raw_spans: RawSpans) -> Vec { diff --git a/minitrace/tests/lib.rs b/minitrace/tests/lib.rs index f049e319..fa227b3e 100644 --- a/minitrace/tests/lib.rs +++ b/minitrace/tests/lib.rs @@ -17,7 +17,7 @@ fn four_spans() { // wide for i in 0..2 { let _span = LocalSpan::enter_with_local_parent(format!("iter-span-{i}")) - .with_property(|| ("tmp_property", "tmp_value")); + .with_property(|| ("tmp_property".into(), "tmp_value".into())); } } @@ -655,3 +655,67 @@ fn test_elapsed() { minitrace::flush(); } + +#[test] +#[serial] +fn test_macro_properties() { + #[trace(short_name = true, properties = { "k1": "v1", "a": "argument a is {a:?}", "b": "{b:?}", "escaped1": "{c:?}{{}}", "escaped2": "{{ \"a\": \"b\"}}" })] + fn foo(a: i64, b: &Bar, c: Bar) { + drop(c); + } + + #[trace(short_name = true, properties = { "k1": "v1", "a": "argument a is {a:?}", "b": "{b:?}", "escaped1": "{c:?}{{}}", "escaped2": "{{ \"a\": \"b\"}}" })] + async fn foo_async(a: i64, b: &Bar, c: Bar) { + drop(c); + } + + #[trace(short_name = true, properties = {})] + fn bar() {} + + #[trace(short_name = true, properties = {})] + async fn bar_async() {} + + #[derive(Debug)] + struct Bar; + + let (reporter, collected_spans) = TestReporter::new(); + minitrace::set_reporter(reporter, Config::default()); + + { + let root = Span::root("root", SpanContext::random()); + let _g = root.set_local_parent(); + foo(1, &Bar, Bar); + bar(); + + let runtime = Builder::new_multi_thread() + .worker_threads(4) + .enable_all() + .build() + .unwrap(); + + block_on( + runtime.spawn( + async { + foo_async(1, &Bar, Bar).await; + bar_async().await; + } + .in_span(root), + ), + ) + .unwrap(); + } + + minitrace::flush(); + + let expected_graph = r#" +root [] + bar [] + bar_async [] + foo [("k1", "v1"), ("a", "argument a is 1"), ("b", "Bar"), ("escaped1", "Bar{}"), ("escaped2", "{ \"a\": \"b\"}")] + foo_async [("k1", "v1"), ("a", "argument a is 1"), ("b", "Bar"), ("escaped1", "Bar{}"), ("escaped2", "{ \"a\": \"b\"}")] +"#; + assert_eq!( + tree_str_from_span_records(collected_spans.lock().clone()), + expected_graph + ); +} diff --git a/test-statically-disable/src/main.rs b/test-statically-disable/src/main.rs index c08c1aeb..02bc5904 100644 --- a/test-statically-disable/src/main.rs +++ b/test-statically-disable/src/main.rs @@ -24,8 +24,8 @@ fn main() { ); let mut root = Span::root("root", SpanContext::new(TraceId(0), SpanId(0))) - .with_property(|| ("k1", "v1")) - .with_properties(|| [("k2", "v2")]); + .with_property(|| ("k1".into(), "v1".into())) + .with_properties(|| [("k2".into(), "v2".into())]); Event::add_to_parent("event", &root, || []); Event::add_to_local_parent("event", || []); @@ -35,8 +35,8 @@ fn main() { Event::add_to_local_parent("event", || []); let _span1 = LocalSpan::enter_with_local_parent("span1") - .with_property(|| ("k", "v")) - .with_properties(|| [("k", "v")]); + .with_property(|| ("k".into(), "v".into())) + .with_properties(|| [("k".into(), "v".into())]); let _span2 = LocalSpan::enter_with_local_parent("span2"); From 257dbfd9722db0bddd42097c06e74fa38c789e62 Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:40:47 +0800 Subject: [PATCH 2/7] fix fmt Signed-off-by: Andy Lok --- minitrace-macro/src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index 6754a617..4952a9dd 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -175,13 +175,14 @@ impl Parse for Args { /// .enter_on_poll("qux") /// .await /// } -/// +/// /// async fn properties(a: u64) { -/// let __span__ = Span::enter_with_local_parent("example::properties") -/// .with_properties(|| [ +/// let __span__ = Span::enter_with_local_parent("example::properties").with_properties(|| { +/// [ /// ("k1".into(), "v1".into()), -/// ("a".into(), format!("argument `a` is {a:?}").into()) -/// ]); +/// ("a".into(), format!("argument `a` is {a:?}").into()), +/// ] +/// }); /// async { /// // ... /// } @@ -323,7 +324,8 @@ fn gen_properties(span: proc_macro2::Span, args: &Args) -> proc_macro2::TokenStr fn unescape_format_string(s: &str) -> (String, bool) { let unescaped_delete = s.replace("{{", "").replace("}}", ""); - let contains_valid_format_string = unescaped_delete.contains("{") || unescaped_delete.contains("}"); + let contains_valid_format_string = + unescaped_delete.contains("{") || unescaped_delete.contains("}"); if contains_valid_format_string { return (s.to_string(), true); } else { From a0fa17631b2149ed7f6837d888ee60a65409d059 Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:43:04 +0800 Subject: [PATCH 3/7] improve Signed-off-by: Andy Lok --- minitrace-macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index 4952a9dd..7559f0b9 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -359,7 +359,7 @@ fn gen_block( } else { quote_spanned!(block.span()=> { - let __span__ = minitrace::Span::enter_with_local_parent( #name ).with_properties(|| [#properties]); + let __span__ = minitrace::Span::enter_with_local_parent( #name ).with_properties(|| [ #properties ]); minitrace::future::FutureExt::in_span( async move { #block }, __span__, @@ -381,7 +381,7 @@ fn gen_block( } quote_spanned!(block.span()=> - let __guard__ = minitrace::local::LocalSpan::enter_with_local_parent( #name ).with_properties(|| [#properties]); + let __guard__ = minitrace::local::LocalSpan::enter_with_local_parent( #name ).with_properties(|| [ #properties ]); #block ) } From 6462d9304f0e75040247c6cb6bca5bac7a8456b0 Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:48:01 +0800 Subject: [PATCH 4/7] improve Signed-off-by: Andy Lok --- minitrace-macro/src/lib.rs | 6 +++--- minitrace/src/local/span_queue.rs | 2 +- minitrace/src/span.rs | 2 +- minitrace/tests/lib.rs | 2 ++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index 7559f0b9..c09d35d1 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -325,12 +325,12 @@ fn gen_properties(span: proc_macro2::Span, args: &Args) -> proc_macro2::TokenStr fn unescape_format_string(s: &str) -> (String, bool) { let unescaped_delete = s.replace("{{", "").replace("}}", ""); let contains_valid_format_string = - unescaped_delete.contains("{") || unescaped_delete.contains("}"); + unescaped_delete.contains('{') || unescaped_delete.contains('}'); if contains_valid_format_string { - return (s.to_string(), true); + (s.to_string(), true) } else { let unescaped_replace = s.replace("{{", "{").replace("}}", "}"); - return (unescaped_replace, false); + (unescaped_replace, false) } } diff --git a/minitrace/src/local/span_queue.rs b/minitrace/src/local/span_queue.rs index 8630f529..4f9eed0f 100644 --- a/minitrace/src/local/span_queue.rs +++ b/minitrace/src/local/span_queue.rs @@ -91,7 +91,7 @@ impl SpanQueue { let span = &mut self.span_queue[span_handle.index]; span.properties - .extend(properties.into_iter().map(|(k, v)| (k.into(), v.into()))); + .extend(properties.into_iter().map(|(k, v)| (k, v))); } #[inline] diff --git a/minitrace/src/span.rs b/minitrace/src/span.rs index 7998b792..216a8784 100644 --- a/minitrace/src/span.rs +++ b/minitrace/src/span.rs @@ -438,7 +438,7 @@ impl SpanInner { { self.raw_span .properties - .extend(properties().into_iter().map(|(k, v)| (k.into(), v.into()))); + .extend(properties().into_iter().map(|(k, v)| (k, v))); } #[inline] diff --git a/minitrace/tests/lib.rs b/minitrace/tests/lib.rs index fa227b3e..637fb953 100644 --- a/minitrace/tests/lib.rs +++ b/minitrace/tests/lib.rs @@ -659,11 +659,13 @@ fn test_elapsed() { #[test] #[serial] fn test_macro_properties() { + #[allow(clippy::drop_non_drop)] #[trace(short_name = true, properties = { "k1": "v1", "a": "argument a is {a:?}", "b": "{b:?}", "escaped1": "{c:?}{{}}", "escaped2": "{{ \"a\": \"b\"}}" })] fn foo(a: i64, b: &Bar, c: Bar) { drop(c); } + #[allow(clippy::drop_non_drop)] #[trace(short_name = true, properties = { "k1": "v1", "a": "argument a is {a:?}", "b": "{b:?}", "escaped1": "{c:?}{{}}", "escaped2": "{{ \"a\": \"b\"}}" })] async fn foo_async(a: i64, b: &Bar, c: Bar) { drop(c); From 76145c77a586667826ed25e8fbfa309349de879f Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:50:55 +0800 Subject: [PATCH 5/7] add Signed-off-by: Andy Lok --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 160b937d..54e75299 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ Feel free to open a PR and add your projects here: - [TiKV](https://github.com/tikv/tikv): A distributed transactional key-value database - [Conductor](https://github.com/the-guild-org/conductor): Open-source GraphQL Gateway +- [Apache OpenDAL](https://github.com/apache/opendal): A data access layer for various storage +- [Databend](https://github.com/datafuselabs/databend): Cost-Effective alternative to Snowflake ## FAQ From 9bf6e3b49b8cd0f332d317b8ff92a0ac5f708922 Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 02:56:00 +0800 Subject: [PATCH 6/7] fix Signed-off-by: Andy Lok --- minitrace-macro/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index c09d35d1..dffa9098 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -295,7 +295,7 @@ fn gen_name(span: proc_macro2::Span, func_name: &str, args: &Args) -> proc_macro fn gen_properties(span: proc_macro2::Span, args: &Args) -> proc_macro2::TokenStream { if args.properties.is_empty() { - return quote!(); + return quote::quote!(); } if args.enter_on_poll { From 038134ac356498c964fa1cbd8e7800e98f3e0fcc Mon Sep 17 00:00:00 2001 From: Andy Lok Date: Thu, 25 Jan 2024 03:08:24 +0800 Subject: [PATCH 7/7] improve Signed-off-by: Andy Lok --- minitrace-macro/src/lib.rs | 19 +++++++----- minitrace/examples/asynchronous.rs | 2 +- minitrace/examples/synchronous.rs | 2 +- minitrace/src/local/local_collector.rs | 6 ++-- minitrace/src/local/local_span.rs | 37 +++++++++++------------ minitrace/src/local/local_span_line.rs | 10 ++++--- minitrace/src/local/local_span_stack.rs | 8 +++-- minitrace/src/local/span_queue.rs | 17 ++++++----- minitrace/src/span.rs | 39 +++++++++++++------------ minitrace/tests/lib.rs | 2 +- test-statically-disable/src/main.rs | 8 ++--- 11 files changed, 81 insertions(+), 69 deletions(-) diff --git a/minitrace-macro/src/lib.rs b/minitrace-macro/src/lib.rs index dffa9098..641d17c7 100644 --- a/minitrace-macro/src/lib.rs +++ b/minitrace-macro/src/lib.rs @@ -179,8 +179,11 @@ impl Parse for Args { /// async fn properties(a: u64) { /// let __span__ = Span::enter_with_local_parent("example::properties").with_properties(|| { /// [ -/// ("k1".into(), "v1".into()), -/// ("a".into(), format!("argument `a` is {a:?}").into()), +/// (std::borrow::Cow::from("k1"), std::borrow::Cow::from("v1")), +/// ( +/// std::borrow::Cow::from("a"), +/// std::borrow::Cow::from(format!("argument `a` is {a:?}")), +/// ), /// ] /// }); /// async { @@ -310,16 +313,18 @@ fn gen_properties(span: proc_macro2::Span, args: &Args) -> proc_macro2::TokenStr if need_format { quote_spanned!(span=> - (#k.into(), format!(#v).into()) + (std::borrow::Cow::from(#k), std::borrow::Cow::from(format!(#v))) ) } else { quote_spanned!(span=> - (#k.into(), #v.into()) + (std::borrow::Cow::from(#k), std::borrow::Cow::from(#v)) ) } }); let properties = Punctuated::<_, Token![,]>::from_iter(properties); - quote_spanned!(span=> #properties) + quote_spanned!(span=> + .with_properties(|| [ #properties ]) + ) } fn unescape_format_string(s: &str) -> (String, bool) { @@ -359,7 +364,7 @@ fn gen_block( } else { quote_spanned!(block.span()=> { - let __span__ = minitrace::Span::enter_with_local_parent( #name ).with_properties(|| [ #properties ]); + let __span__ = minitrace::Span::enter_with_local_parent( #name ) #properties; minitrace::future::FutureExt::in_span( async move { #block }, __span__, @@ -381,7 +386,7 @@ fn gen_block( } quote_spanned!(block.span()=> - let __guard__ = minitrace::local::LocalSpan::enter_with_local_parent( #name ).with_properties(|| [ #properties ]); + let __guard__ = minitrace::local::LocalSpan::enter_with_local_parent( #name ) #properties; #block ) } diff --git a/minitrace/examples/asynchronous.rs b/minitrace/examples/asynchronous.rs index aeb12d0d..ecca53f2 100644 --- a/minitrace/examples/asynchronous.rs +++ b/minitrace/examples/asynchronous.rs @@ -47,7 +47,7 @@ async fn main() { let f = async { let jhs = { let _span = LocalSpan::enter_with_local_parent("a span") - .with_property(|| ("a property".into(), "a value".into())); + .with_property(|| ("a property", "a value")); parallel_job() }; diff --git a/minitrace/examples/synchronous.rs b/minitrace/examples/synchronous.rs index 44b620db..2650d690 100644 --- a/minitrace/examples/synchronous.rs +++ b/minitrace/examples/synchronous.rs @@ -31,7 +31,7 @@ async fn main() { let _g = root.set_local_parent(); let _span = LocalSpan::enter_with_local_parent("a span") - .with_property(|| ("a property".into(), "a value".into())); + .with_property(|| ("a property", "a value")); for i in 1..=10 { func1(i); diff --git a/minitrace/src/local/local_collector.rs b/minitrace/src/local/local_collector.rs index c0e8456c..a16e7075 100644 --- a/minitrace/src/local/local_collector.rs +++ b/minitrace/src/local/local_collector.rs @@ -316,10 +316,8 @@ span1 [] #[test] fn local_spans_to_span_record() { let collector = LocalCollector::start(); - let span1 = LocalSpan::enter_with_local_parent("span1") - .with_property(|| ("k1".into(), "v1".into())); - let span2 = LocalSpan::enter_with_local_parent("span2") - .with_property(|| ("k2".into(), "v2".into())); + let span1 = LocalSpan::enter_with_local_parent("span1").with_property(|| ("k1", "v1")); + let span2 = LocalSpan::enter_with_local_parent("span2").with_property(|| ("k2", "v2")); drop(span2); drop(span1); diff --git a/minitrace/src/local/local_span.rs b/minitrace/src/local/local_span.rs index d797d754..466cab3a 100644 --- a/minitrace/src/local/local_span.rs +++ b/minitrace/src/local/local_span.rs @@ -63,12 +63,16 @@ impl LocalSpan { /// ``` /// use minitrace::prelude::*; /// - /// let span = LocalSpan::enter_with_local_parent("a child span") - /// .with_property(|| ("key".into(), "value".into())); + /// let span = + /// LocalSpan::enter_with_local_parent("a child span").with_property(|| ("key", "value")); /// ``` #[inline] - pub fn with_property(self, property: F) -> Self - where F: FnOnce() -> (Cow<'static, str>, Cow<'static, str>) { + pub fn with_property(self, property: F) -> Self + where + K: Into>, + V: Into>, + F: FnOnce() -> (K, V), + { self.with_properties(|| [property()]) } @@ -79,17 +83,15 @@ impl LocalSpan { /// ``` /// use minitrace::prelude::*; /// - /// let span = LocalSpan::enter_with_local_parent("a child span").with_properties(|| { - /// [ - /// ("key1".into(), "value1".into()), - /// ("key2".into(), "value2".into()), - /// ] - /// }); + /// let span = LocalSpan::enter_with_local_parent("a child span") + /// .with_properties(|| [("key1", "value1"), ("key2", "value2")]); /// ``` #[inline] - pub fn with_properties(self, properties: F) -> Self + pub fn with_properties(self, properties: F) -> Self where - I: IntoIterator, Cow<'static, str>)>, + K: Into>, + V: Into>, + I: IntoIterator, F: FnOnce() -> I, { #[cfg(feature = "enable")] @@ -159,8 +161,8 @@ mod tests { { let _g = LocalSpan::enter_with_stack("span1", stack.clone()); { - let _span = LocalSpan::enter_with_stack("span2", stack) - .with_property(|| ("k1".into(), "v1".into())); + let _span = + LocalSpan::enter_with_stack("span2", stack).with_property(|| ("k1", "v1")); } } @@ -177,8 +179,7 @@ span1 [] #[test] fn local_span_noop() { - let _span1 = LocalSpan::enter_with_local_parent("span1") - .with_property(|| ("k1".into(), "v1".into())); + let _span1 = LocalSpan::enter_with_local_parent("span1").with_property(|| ("k1", "v1")); } #[test] @@ -197,8 +198,8 @@ span1 [] { let span1 = LocalSpan::enter_with_stack("span1", stack.clone()); { - let _span2 = LocalSpan::enter_with_stack("span2", stack) - .with_property(|| ("k1".into(), "v1".into())); + let _span2 = + LocalSpan::enter_with_stack("span2", stack).with_property(|| ("k1", "v1")); drop(span1); } diff --git a/minitrace/src/local/local_span_line.rs b/minitrace/src/local/local_span_line.rs index 7743cfc8..b7dea471 100644 --- a/minitrace/src/local/local_span_line.rs +++ b/minitrace/src/local/local_span_line.rs @@ -57,9 +57,11 @@ impl SpanLine { } #[inline] - pub fn add_properties(&mut self, handle: &LocalSpanHandle, properties: F) + pub fn add_properties(&mut self, handle: &LocalSpanHandle, properties: F) where - I: IntoIterator, Cow<'static, str>)>, + K: Into>, + V: Into>, + I: IntoIterator, F: FnOnce() -> I, { if self.epoch == handle.span_line_epoch { @@ -111,7 +113,7 @@ mod tests { let span2 = span_line.start_span("span2").unwrap(); { let span3 = span_line.start_span("span3").unwrap(); - span_line.add_properties(&span3, || [("k1".into(), "v1".into())]); + span_line.add_properties(&span3, || [("k1", "v1")]); span_line.finish_span(span3); } span_line.finish_span(span2); @@ -190,7 +192,7 @@ span [] assert_eq!(span_line2.span_line_epoch(), 2); let span = span_line1.start_span("span").unwrap(); - span_line2.add_properties(&span, || [("k1".into(), "v1".into())]); + span_line2.add_properties(&span, || [("k1", "v1")]); span_line1.finish_span(span); let raw_spans = span_line1.collect(1).unwrap().0.into_inner(); diff --git a/minitrace/src/local/local_span_stack.rs b/minitrace/src/local/local_span_stack.rs index 72967a97..50c52d3e 100644 --- a/minitrace/src/local/local_span_stack.rs +++ b/minitrace/src/local/local_span_stack.rs @@ -98,9 +98,11 @@ impl LocalSpanStack { } #[inline] - pub fn add_properties(&mut self, local_span_handle: &LocalSpanHandle, properties: F) + pub fn add_properties(&mut self, local_span_handle: &LocalSpanHandle, properties: F) where - I: IntoIterator, Cow<'static, str>)>, + K: Into>, + V: Into>, + I: IntoIterator, F: FnOnce() -> I, { debug_assert!(self.current_span_line().is_some()); @@ -355,7 +357,7 @@ span1 [] .into(), )) .unwrap(); - span_stack.add_properties(&span1, || [("k1".into(), "v1".into())]); + span_stack.add_properties(&span1, || [("k1", "v1")]); let _ = span_stack.unregister_and_collect(span_line2).unwrap(); } span_stack.exit_span(span1); diff --git a/minitrace/src/local/span_queue.rs b/minitrace/src/local/span_queue.rs index 4f9eed0f..f168fe8c 100644 --- a/minitrace/src/local/span_queue.rs +++ b/minitrace/src/local/span_queue.rs @@ -85,13 +85,17 @@ impl SpanQueue { } #[inline] - pub fn add_properties(&mut self, span_handle: &SpanHandle, properties: I) - where I: IntoIterator, Cow<'static, str>)> { + pub fn add_properties(&mut self, span_handle: &SpanHandle, properties: I) + where + K: Into>, + V: Into>, + I: IntoIterator, + { debug_assert!(span_handle.index < self.span_queue.len()); let span = &mut self.span_queue[span_handle.index]; span.properties - .extend(properties.into_iter().map(|(k, v)| (k, v))); + .extend(properties.into_iter().map(|(k, v)| (k.into(), v.into()))); } #[inline] @@ -145,13 +149,10 @@ span1 [] let mut queue = SpanQueue::with_capacity(16); { let span1 = queue.start_span("span1").unwrap(); - queue.add_properties(&span1, [ - ("k1".into(), "v1".into()), - ("k2".into(), "v2".into()), - ]); + queue.add_properties(&span1, [("k1", "v1"), ("k2", "v2")]); { let span2 = queue.start_span("span2").unwrap(); - queue.add_properties(&span2, [("k1".into(), "v1".into())]); + queue.add_properties(&span2, [("k1", "v1")]); queue.finish_span(span2); } queue.finish_span(span1); diff --git a/minitrace/src/span.rs b/minitrace/src/span.rs index 216a8784..08529a73 100644 --- a/minitrace/src/span.rs +++ b/minitrace/src/span.rs @@ -250,12 +250,15 @@ impl Span { /// ``` /// use minitrace::prelude::*; /// - /// let root = - /// Span::root("root", SpanContext::random()).with_property(|| ("key".into(), "value".into())); + /// let root = Span::root("root", SpanContext::random()).with_property(|| ("key", "value")); /// ``` #[inline] - pub fn with_property(self, property: F) -> Self - where F: FnOnce() -> (Cow<'static, str>, Cow<'static, str>) { + pub fn with_property(self, property: F) -> Self + where + K: Into>, + V: Into>, + F: FnOnce() -> (K, V), + { self.with_properties(move || [property()]) } @@ -266,17 +269,15 @@ impl Span { /// ``` /// use minitrace::prelude::*; /// - /// let root = Span::root("root", SpanContext::random()).with_properties(|| { - /// [ - /// ("key1".into(), "value1".into()), - /// ("key2".into(), "value2".into()), - /// ] - /// }); + /// let root = Span::root("root", SpanContext::random()) + /// .with_properties(|| [("key1", "value1"), ("key2", "value2")]); /// ``` #[inline] - pub fn with_properties(mut self, properties: F) -> Self + pub fn with_properties(mut self, properties: F) -> Self where - I: IntoIterator, Cow<'static, str>)>, + K: Into>, + V: Into>, + I: IntoIterator, F: FnOnce() -> I, { #[cfg(feature = "enable")] @@ -431,14 +432,16 @@ impl Span { #[cfg(feature = "enable")] impl SpanInner { #[inline] - fn add_properties(&mut self, properties: F) + fn add_properties(&mut self, properties: F) where - I: IntoIterator, Cow<'static, str>)>, + K: Into>, + V: Into>, + I: IntoIterator, F: FnOnce() -> I, { self.raw_span .properties - .extend(properties().into_iter().map(|(k, v)| (k, v))); + .extend(properties().into_iter().map(|(k, v)| (k.into(), v.into()))); } #[inline] @@ -640,8 +643,8 @@ mod tests { let routine = |collect| { let parent_ctx = SpanContext::random(); let root = Span::root("root", parent_ctx, collect); - let child1 = Span::enter_with_parent("child1", &root) - .with_properties(|| [("k1".into(), "v1".into())]); + let child1 = + Span::enter_with_parent("child1", &root).with_properties(|| [("k1", "v1")]); let grandchild = Span::enter_with_parent("grandchild", &child1); let child2 = Span::enter_with_parent("child2", &root); @@ -709,7 +712,7 @@ root [] [&parent1, &parent2, &parent3, &parent4, &parent5, &child1], collect, ) - .with_property(|| ("k1".into(), "v1".into())); + .with_property(|| ("k1", "v1")); crossbeam::scope(move |scope| { let mut rng = thread_rng(); diff --git a/minitrace/tests/lib.rs b/minitrace/tests/lib.rs index 637fb953..6ffdd03c 100644 --- a/minitrace/tests/lib.rs +++ b/minitrace/tests/lib.rs @@ -17,7 +17,7 @@ fn four_spans() { // wide for i in 0..2 { let _span = LocalSpan::enter_with_local_parent(format!("iter-span-{i}")) - .with_property(|| ("tmp_property".into(), "tmp_value".into())); + .with_property(|| ("tmp_property", "tmp_value")); } } diff --git a/test-statically-disable/src/main.rs b/test-statically-disable/src/main.rs index 02bc5904..c08c1aeb 100644 --- a/test-statically-disable/src/main.rs +++ b/test-statically-disable/src/main.rs @@ -24,8 +24,8 @@ fn main() { ); let mut root = Span::root("root", SpanContext::new(TraceId(0), SpanId(0))) - .with_property(|| ("k1".into(), "v1".into())) - .with_properties(|| [("k2".into(), "v2".into())]); + .with_property(|| ("k1", "v1")) + .with_properties(|| [("k2", "v2")]); Event::add_to_parent("event", &root, || []); Event::add_to_local_parent("event", || []); @@ -35,8 +35,8 @@ fn main() { Event::add_to_local_parent("event", || []); let _span1 = LocalSpan::enter_with_local_parent("span1") - .with_property(|| ("k".into(), "v".into())) - .with_properties(|| [("k".into(), "v".into())]); + .with_property(|| ("k", "v")) + .with_properties(|| [("k", "v")]); let _span2 = LocalSpan::enter_with_local_parent("span2");