From 95f6809dfa12b03a3f81cf17841956ce7c3b693f Mon Sep 17 00:00:00 2001 From: Jonas Platte <158304798+svix-jplatte@users.noreply.github.com> Date: Fri, 5 Jul 2024 14:05:33 +0200 Subject: [PATCH] macros: allow field path segments to be keywords (#2925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, a keyword like `type` fails compilation as (a path segment of) a field name, for no clear reason. Trying to use `r#type` instead leads to the `r#` being part of the field name, which is unhelpful¹. Don't require the field path to match a `macro_rules!` `expr`, use repeated `tt` instead. I can't tell why this was ever required: The internal stringify macro was introduced in https://github.com/tokio-rs/tracing/commit/55091c92edb537bfc126e32f1f24acd614ad9fe0#diff-315c02cd05738da173861537577d159833f70f79cfda8cd7cf1a0d7a28ace31b with an `expr` matcher without any explanation, and no tests are failing from making it match upstream's `stringify!` input format. Special thanks to whoever implemented the unstable `macro-backtrace` feature in rustc, otherwise this would have been nigh impossible to track down! ¹ this can likely be fixed too by some sort of "unraw" macro that turns `r#foo` into `foo`, but that's a separate change not made in this PR --- tracing-attributes/tests/fields.rs | 13 +++++++++++++ tracing/src/macros.rs | 4 ++-- tracing/tests/event.rs | 12 ++++++++++++ tracing/tests/span.rs | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/tracing-attributes/tests/fields.rs b/tracing-attributes/tests/fields.rs index 35b69967e..3f9dce667 100644 --- a/tracing-attributes/tests/fields.rs +++ b/tracing-attributes/tests/fields.rs @@ -34,6 +34,9 @@ fn fn_string(s: String) { let _ = s; } +#[instrument(fields(keywords.impl.type.fn = _arg), skip(_arg))] +fn fn_keyword_ident_in_field(_arg: &str) {} + #[derive(Debug)] struct HasField { my_field: &'static str, @@ -146,6 +149,16 @@ fn string_field() { }); } +#[test] +fn keyword_ident_in_field_name() { + let span = expect::span().with_fields( + expect::field("keywords.impl.type.fn") + .with_value(&"test") + .only(), + ); + run_test(span, || fn_keyword_ident_in_field("test")); +} + fn run_test T, T>(span: NewSpan, fun: F) { let (subscriber, handle) = subscriber::mock() .new_span(span) diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs index 5e9f65d07..e7cbf9546 100644 --- a/tracing/src/macros.rs +++ b/tracing/src/macros.rs @@ -3066,8 +3066,8 @@ macro_rules! level_to_log { #[doc(hidden)] #[macro_export] macro_rules! __tracing_stringify { - ($s:expr) => { - stringify!($s) + ($($t:tt)*) => { + stringify!($($t)*) }; } diff --git a/tracing/tests/event.rs b/tracing/tests/event.rs index 55e9b81bc..973eb4bff 100644 --- a/tracing/tests/event.rs +++ b/tracing/tests/event.rs @@ -606,3 +606,15 @@ fn constant_field_name() { handle.assert_finished(); } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[test] +fn keyword_ident_in_field_name() { + let (collector, handle) = collector::mock() + .event(expect::event().with_fields(expect::field("crate").with_value(&"tracing"))) + .only() + .run_with_handle(); + + with_default(collector, || error!(crate = "tracing", "message")); + handle.assert_finished(); +} diff --git a/tracing/tests/span.rs b/tracing/tests/span.rs index bd5bed0d2..9f4e5c45b 100644 --- a/tracing/tests/span.rs +++ b/tracing/tests/span.rs @@ -6,6 +6,7 @@ use std::thread; use tracing::{ + error_span, field::{debug, display}, subscriber::with_default, Level, Span, @@ -898,3 +899,20 @@ fn constant_field_name() { handle.assert_finished(); } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[test] +fn keyword_ident_in_field_name_span_macro() { + #[derive(Debug)] + struct Foo; + + let (subscriber, handle) = subscriber::mock() + .new_span(expect::span().with_fields(expect::field("self").with_value(&debug(Foo)).only())) + .only() + .run_with_handle(); + + with_default(subscriber, || { + error_span!("span", self = ?Foo); + }); + handle.assert_finished(); +}