From e4ee3a5e4754de586203621395879c54e2be032c Mon Sep 17 00:00:00 2001 From: Sleep_AllDay <37238439+SpeedReach@users.noreply.github.com> Date: Wed, 15 Nov 2023 02:08:35 +0800 Subject: [PATCH 01/21] subscriber: fix flaky reload tests (#2798) fixes https://github.com/tokio-rs/tracing/actions/runs/6785393202/job/18443641813 cargo test runs tests in the same file in parallel by default, causing race condition, this can be proven by running `cargo test --test reload -- --test-threads=1` => successes `cargo test --test reload -- --test-threads=2` => flaky multiple times This fix runs only the two tests in serial. We could seperate the tests in different files, but they share the same testing dependencies, so I left them in the same file. --- tracing-subscriber/tests/reload.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tracing-subscriber/tests/reload.rs b/tracing-subscriber/tests/reload.rs index 28662e2e6f..8b48cc203b 100644 --- a/tracing-subscriber/tests/reload.rs +++ b/tracing-subscriber/tests/reload.rs @@ -32,7 +32,15 @@ impl Subscriber for NopSubscriber { fn exit(&self, _: &Id) {} } +/// Running these two tests in parallel will cause flaky failures, since they are both modifying the MAX_LEVEL value. +/// "cargo test -- --test-threads=1 fixes it, but it runs all tests in serial. +/// The only way to run tests in serial in a single file is this way. #[test] +fn run_all_reload_test() { + reload_handle(); + reload_filter(); +} + fn reload_handle() { static FILTER1_CALLS: AtomicUsize = AtomicUsize::new(0); static FILTER2_CALLS: AtomicUsize = AtomicUsize::new(0); @@ -89,7 +97,6 @@ fn reload_handle() { }) } -#[test] fn reload_filter() { struct NopLayer; impl tracing_subscriber::Layer for NopLayer { From 98834389f737646d8de086beee87c05efa1a4b74 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 6 Jan 2024 11:28:11 -0800 Subject: [PATCH 02/21] examples: suppress false positive clippy lint (#2846) Signed-off-by: Alex Saveau --- examples/examples/sloggish/sloggish_subscriber.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/examples/sloggish/sloggish_subscriber.rs b/examples/examples/sloggish/sloggish_subscriber.rs index e551811557..4cbc1385d8 100644 --- a/examples/examples/sloggish/sloggish_subscriber.rs +++ b/examples/examples/sloggish/sloggish_subscriber.rs @@ -239,6 +239,7 @@ impl Subscriber for SloggishSubscriber { self.print_indent(&mut stderr, indent).unwrap(); stack.push(span_id.clone()); if let Some(data) = data { + #[allow(clippy::map_identity)] // TODO remove in Rust 1.77 self.print_kvs(&mut stderr, data.kvs.iter().map(|(k, v)| (k, v)), "") .unwrap(); } From 182420f992d99d928256aaa71fbbc3962bdab863 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 7 Jan 2024 06:10:05 +0900 Subject: [PATCH 03/21] chore(ci): update actions/checkout action to v4 (#2845) --- .github/workflows/audit.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f4d89ead1f..ccd30acee6 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -29,7 +29,7 @@ jobs: security_audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions-rs/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 77a52ca806..c175cfe762 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'tokio-rs' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: taiki-e/create-gh-release-action@v1 with: prefix: tracing(-[a-z]+)? From a8ae276fb2321b7539f2d9f6bcdbecf9ca2d5f41 Mon Sep 17 00:00:00 2001 From: Gabriel Goller Date: Thu, 11 Jan 2024 21:28:41 +0100 Subject: [PATCH 04/21] journald: make level mappings configurable (#2824) This allows to manually map tracing levels to journald levels. It seems that @little-dude, who started the original PR, doesn't have time to finish this, so I picked it up. Reapplied the changes to the newest master branch and fixed the latest comments/issues. This will also fix/close: Closes #2649 Closes #2661 Closes #2347 (the original pr) --- tracing-journald/src/lib.rs | 177 +++++++++++++++++++++++++++--- tracing-journald/tests/journal.rs | 50 ++++++++- 2 files changed, 210 insertions(+), 17 deletions(-) diff --git a/tracing-journald/src/lib.rs b/tracing-journald/src/lib.rs index d7229af801..3f0e561284 100644 --- a/tracing-journald/src/lib.rs +++ b/tracing-journald/src/lib.rs @@ -60,7 +60,7 @@ mod socket; /// names by translating `.`s into `_`s, stripping leading `_`s and non-ascii-alphanumeric /// characters other than `_`, and upcasing. /// -/// Levels are mapped losslessly to journald `PRIORITY` values as follows: +/// By default, levels are mapped losslessly to journald `PRIORITY` values as follows: /// /// - `ERROR` => Error (3) /// - `WARN` => Warning (4) @@ -68,6 +68,8 @@ mod socket; /// - `DEBUG` => Informational (6) /// - `TRACE` => Debug (7) /// +/// These mappings can be changed with [`Subscriber::with_priority_mappings`]. +/// /// The standard journald `CODE_LINE` and `CODE_FILE` fields are automatically emitted. A `TARGET` /// field is emitted containing the event's target. /// @@ -84,6 +86,7 @@ pub struct Layer { field_prefix: Option, syslog_identifier: String, additional_fields: Vec, + priority_mappings: PriorityMappings, } #[cfg(unix)] @@ -109,6 +112,7 @@ impl Layer { // If we fail to get the name of the current executable fall back to an empty string. .unwrap_or_default(), additional_fields: Vec::new(), + priority_mappings: PriorityMappings::new(), }; // Check that we can talk to journald, by sending empty payload which journald discards. // However if the socket didn't exist or if none listened we'd get an error here. @@ -129,6 +133,41 @@ impl Layer { self } + /// Sets how [`tracing_core::Level`]s are mapped to [journald priorities](Priority). + /// + /// # Examples + /// + /// ```rust + /// use tracing_journald::{Priority, PriorityMappings}; + /// use tracing_subscriber::prelude::*; + /// use tracing::error; + /// + /// let registry = tracing_subscriber::registry(); + /// match tracing_journald::layer() { + /// Ok(layer) => { + /// registry.with( + /// layer + /// // We can tweak the mappings between the trace level and + /// // the journal priorities. + /// .with_priority_mappings(PriorityMappings { + /// info: Priority::Informational, + /// ..PriorityMappings::new() + /// }), + /// ); + /// } + /// // journald is typically available on Linux systems, but nowhere else. Portable software + /// // should handle its absence gracefully. + /// Err(e) => { + /// registry.init(); + /// error!("couldn't connect to journald: {}", e); + /// } + /// } + /// ``` + pub fn with_priority_mappings(mut self, mappings: PriorityMappings) -> Self { + self.priority_mappings = mappings; + self + } + /// Sets the syslog identifier for this logger. /// /// The syslog identifier comes from the classic syslog interface (`openlog()` @@ -232,6 +271,20 @@ impl Layer { memfd::seal_fully(mem.as_raw_fd())?; socket::send_one_fd_to(&self.socket, mem.as_raw_fd(), JOURNALD_PATH) } + + fn put_priority(&self, buf: &mut Vec, meta: &Metadata) { + put_field_wellformed( + buf, + "PRIORITY", + &[match *meta.level() { + Level::ERROR => self.priority_mappings.error as u8, + Level::WARN => self.priority_mappings.warn as u8, + Level::INFO => self.priority_mappings.info as u8, + Level::DEBUG => self.priority_mappings.debug as u8, + Level::TRACE => self.priority_mappings.trace as u8, + }], + ); + } } /// Construct a journald layer @@ -286,7 +339,7 @@ where } // Record event fields - put_priority(&mut buf, event.metadata()); + self.put_priority(&mut buf, event.metadata()); put_metadata(&mut buf, event.metadata(), None); put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| { write!(buf, "{}", self.syslog_identifier).unwrap() @@ -374,18 +427,114 @@ impl Visit for EventVisitor<'_> { } } -fn put_priority(buf: &mut Vec, meta: &Metadata) { - put_field_wellformed( - buf, - "PRIORITY", - match *meta.level() { - Level::ERROR => b"3", - Level::WARN => b"4", - Level::INFO => b"5", - Level::DEBUG => b"6", - Level::TRACE => b"7", - }, - ); +/// A priority (called "severity code" by syslog) is used to mark the +/// importance of a message. +/// +/// Descriptions and examples are taken from the [Arch Linux wiki]. +/// Priorities are also documented in the +/// [section 6.2.1 of the Syslog protocol RFC][syslog]. +/// +/// [Arch Linux wiki]: https://wiki.archlinux.org/title/Systemd/Journal#Priority_level +/// [syslog]: https://www.rfc-editor.org/rfc/rfc5424#section-6.2.1 +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +#[repr(u8)] +pub enum Priority { + /// System is unusable. + /// + /// Examples: + /// + /// - severe Kernel BUG + /// - systemd dumped core + /// + /// This level should not be used by applications. + Emergency = b'0', + /// Should be corrected immediately. + /// + /// Examples: + /// + /// - Vital subsystem goes out of work, data loss: + /// - `kernel: BUG: unable to handle kernel paging request at ffffc90403238ffc` + Alert = b'1', + /// Critical conditions + /// + /// Examples: + /// + /// - Crashe, coredumps + /// - `systemd-coredump[25319]: Process 25310 (plugin-container) of user 1000 dumped core` + Critical = b'2', + /// Error conditions + /// + /// Examples: + /// + /// - Not severe error reported + /// - `kernel: usb 1-3: 3:1: cannot get freq at ep 0x84, systemd[1]: Failed unmounting /var` + /// - `libvirtd[1720]: internal error: Failed to initialize a valid firewall backend` + Error = b'3', + /// May indicate that an error will occur if action is not taken. + /// + /// Examples: + /// + /// - a non-root file system has only 1GB free + /// - `org.freedesktop. Notifications[1860]: (process:5999): Gtk-WARNING **: Locale not supported by C library. Using the fallback 'C' locale` + Warning = b'4', + /// Events that are unusual, but not error conditions. + /// + /// Examples: + /// + /// - `systemd[1]: var.mount: Directory /var to mount over is not empty, mounting anyway` + /// - `gcr-prompter[4997]: Gtk: GtkDialog mapped without a transient parent. This is discouraged` + Notice = b'5', + /// Normal operational messages that require no action. + /// + /// Example: `lvm[585]: 7 logical volume(s) in volume group "archvg" now active` + Informational = b'6', + /// Information useful to developers for debugging the + /// application. + /// + /// Example: `kdeinit5[1900]: powerdevil: Scheduling inhibition from ":1.14" "firefox" with cookie 13 and reason "screen"` + Debug = b'7', +} + +/// Mappings from tracing [`Level`]s to journald [priorities]. +/// +/// [priorities]: Priority +#[derive(Debug, Clone)] +pub struct PriorityMappings { + /// Priority mapped to the `ERROR` level + pub error: Priority, + /// Priority mapped to the `WARN` level + pub warn: Priority, + /// Priority mapped to the `INFO` level + pub info: Priority, + /// Priority mapped to the `DEBUG` level + pub debug: Priority, + /// Priority mapped to the `TRACE` level + pub trace: Priority, +} + +impl PriorityMappings { + /// Returns the default priority mappings: + /// + /// - [`tracing::Level::ERROR`]: [`Priority::Error`] (3) + /// - [`tracing::Level::WARN`]: [`Priority::Warning`] (4) + /// - [`tracing::Level::INFO`]: [`Priority::Notice`] (5) + /// - [`tracing::Level::DEBUG`]: [`Priority::Informational`] (6) + /// - [`tracing::Level::TRACE`]: [`Priority::Debug`] (7) + pub fn new() -> PriorityMappings { + Self { + error: Priority::Error, + warn: Priority::Warning, + info: Priority::Notice, + debug: Priority::Informational, + trace: Priority::Debug, + } + } +} + +impl Default for PriorityMappings { + fn default() -> Self { + Self::new() + } } fn put_metadata(buf: &mut Vec, meta: &Metadata, prefix: Option<&str>) { diff --git a/tracing-journald/tests/journal.rs b/tracing-journald/tests/journal.rs index c2f3010879..65379c1fd2 100644 --- a/tracing-journald/tests/journal.rs +++ b/tracing-journald/tests/journal.rs @@ -6,8 +6,8 @@ use std::time::Duration; use serde::Deserialize; -use tracing::{debug, error, info, info_span, warn}; -use tracing_journald::Layer; +use tracing::{debug, error, info, info_span, trace, warn}; +use tracing_journald::{Layer, Priority, PriorityMappings}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::Registry; @@ -17,7 +17,16 @@ fn journalctl_version() -> std::io::Result { } fn with_journald(f: impl FnOnce()) { - with_journald_layer(Layer::new().unwrap().with_field_prefix(None), f) + with_journald_layer( + Layer::new() + .unwrap() + .with_field_prefix(None) + .with_priority_mappings(PriorityMappings { + trace: Priority::Informational, + ..PriorityMappings::new() + }), + f, + ) } fn with_journald_layer(layer: Layer, f: impl FnOnce()) { @@ -168,6 +177,41 @@ fn simple_message() { }); } +#[test] +fn custom_priorities() { + fn check_message(level: &str, priority: &str) { + let entry = retry_read_one_line_from_journal(&format!("custom_priority.{}", level)); + assert_eq!(entry["MESSAGE"], format!("hello {}", level).as_str()); + assert_eq!(entry["PRIORITY"], priority); + } + + let priorities = PriorityMappings { + error: Priority::Critical, + warn: Priority::Error, + info: Priority::Warning, + debug: Priority::Notice, + trace: Priority::Informational, + }; + let layer = Layer::new() + .unwrap() + .with_field_prefix(None) + .with_priority_mappings(priorities); + let test = || { + trace!(test.name = "custom_priority.trace", "hello trace"); + check_message("trace", "6"); + debug!(test.name = "custom_priority.debug", "hello debug"); + check_message("debug", "5"); + info!(test.name = "custom_priority.info", "hello info"); + check_message("info", "4"); + warn!(test.name = "custom_priority.warn", "hello warn"); + check_message("warn", "3"); + error!(test.name = "custom_priority.error", "hello error"); + check_message("error", "2"); + }; + + with_journald_layer(layer, test); +} + #[test] fn multiline_message() { with_journald(|| { From 4f08512489080c0a5550408836d272c1f970511c Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Tue, 16 Jan 2024 03:43:42 +0800 Subject: [PATCH 05/21] chore: Fix spelling (#2854) --- tracing-core/src/metadata.rs | 2 +- tracing-error/CHANGELOG.md | 2 +- tracing-error/src/error.rs | 4 ++-- tracing-subscriber/CHANGELOG.md | 12 ++++++------ tracing-subscriber/src/filter/env/mod.rs | 2 +- tracing-subscriber/src/filter/filter_fn.rs | 2 +- tracing-subscriber/src/filter/layer_filters/mod.rs | 2 +- tracing-subscriber/src/filter/mod.rs | 2 +- tracing-subscriber/src/fmt/format/mod.rs | 2 +- tracing-subscriber/src/fmt/time/datetime.rs | 2 +- tracing-subscriber/src/layer/mod.rs | 8 ++++---- tracing/CHANGELOG.md | 2 +- tracing/README.md | 4 ++-- tracing/src/lib.rs | 2 +- tracing/src/macros.rs | 2 +- tracing/tests/enabled.rs | 2 +- 16 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tracing-core/src/metadata.rs b/tracing-core/src/metadata.rs index 7d8448b641..5cec421899 100644 --- a/tracing-core/src/metadata.rs +++ b/tracing-core/src/metadata.rs @@ -377,7 +377,7 @@ impl Kind { pub const SPAN: Kind = Kind(Self::SPAN_BIT); /// `enabled!` callsite. [`Subscriber`][`crate::subscriber::Subscriber`]s can assume - /// this `Kind` means they will never recieve a + /// this `Kind` means they will never receive a /// full event with this [`Metadata`]. pub const HINT: Kind = Kind(Self::HINT_BIT); diff --git a/tracing-error/CHANGELOG.md b/tracing-error/CHANGELOG.md index 7cd565dcfe..bd966591dc 100644 --- a/tracing-error/CHANGELOG.md +++ b/tracing-error/CHANGELOG.md @@ -35,7 +35,7 @@ Thanks to @CAD97 for contributing to this release! - **TracedError**: `TracedError`, an error type wrapper that annotates an error with the current span. - **SpanTrace**:`SpanTrace::status` method and `SpanTraceStatus` type for - determing whether a `SpanTrace` was successfully captured (#614) + determining whether a `SpanTrace` was successfully captured (#614) ### Changed diff --git a/tracing-error/src/error.rs b/tracing-error/src/error.rs index f28d0c39fd..74c50fb445 100644 --- a/tracing-error/src/error.rs +++ b/tracing-error/src/error.rs @@ -73,8 +73,8 @@ where // erased `ErrorImpl` back to its original type, which is needed in order to forward our // error/display/debug impls to the internal error type from the type erased error type. // - // The repr(C) is necessary to ensure that the struct is layed out in the order we - // specified it so that we can safely access the vtable and spantrace fields thru a type + // The repr(C) is necessary to ensure that the struct is laid out in the order we + // specified it, so that we can safely access the vtable and spantrace fields through a type // erased pointer to the original object. let vtable = &ErrorVTable { object_ref: object_ref::, diff --git a/tracing-subscriber/CHANGELOG.md b/tracing-subscriber/CHANGELOG.md index a8894b9ea2..7f0c551e89 100644 --- a/tracing-subscriber/CHANGELOG.md +++ b/tracing-subscriber/CHANGELOG.md @@ -972,7 +972,7 @@ Thanks to @bdonlan and @jeromegn for contributing to this release! ### Changed - **filter**: `LevelFilter` is now a re-export of the - `tracing_core::LevelFilter` type, it can now be used interchangably with the + `tracing_core::LevelFilter` type, it can now be used interchangeably with the versions in `tracing` and `tracing-core` (#853) - **filter**: Significant performance improvements when comparing `LevelFilter`s and `Level`s (#853) @@ -1175,7 +1175,7 @@ tuning in this release! - **fmt**: Fixed empty `{}` printed after spans with no fields (f079f2d) - **fmt**: Fixed inconsistent formatting when ANSI colors are disabled (506a482) -- **fmt**: Fixed mis-aligned levels when ANSI colors are disabled (eba1adb) +- **fmt**: Fixed misaligned levels when ANSI colors are disabled (eba1adb) - Fixed warnings on nightly Rust compilers (#558) # 0.2.0-alpha.5 (January 31, 2020) @@ -1262,9 +1262,9 @@ tuning in this release! changes in subsequent alpha. (#420, #425) - **BREAKING**: Removed `Filter`. Use `EnvFilter` instead (#434) -### Contributers +### Contributors -Thanks to all the contributers to this release! +Thanks to all the contributors to this release! - @pimeys for #377 and #415 @@ -1290,9 +1290,9 @@ Thanks to all the contributers to this release! order to initialize the global logger. Only `tracing-log` needs to be specified now (#400). -### Contributers +### Contributors -Thanks to all the contributers to this release! +Thanks to all the contributors to this release! - @emschwartz for #385, #387, #400 and #401 - @bIgBV for #388 diff --git a/tracing-subscriber/src/filter/env/mod.rs b/tracing-subscriber/src/filter/env/mod.rs index 81a9ae2bde..813e32b447 100644 --- a/tracing-subscriber/src/filter/env/mod.rs +++ b/tracing-subscriber/src/filter/env/mod.rs @@ -479,7 +479,7 @@ impl EnvFilter { let level = metadata.level(); // is it possible for a dynamic filter directive to enable this event? - // if not, we can avoid the thread loca'l access + iterating over the + // if not, we can avoid the thread local access + iterating over the // spans in the current scope. if self.has_dynamics && self.dynamics.max_level >= *level { if metadata.is_span() { diff --git a/tracing-subscriber/src/filter/filter_fn.rs b/tracing-subscriber/src/filter/filter_fn.rs index 332bf860a6..b57c30b294 100644 --- a/tracing-subscriber/src/filter/filter_fn.rs +++ b/tracing-subscriber/src/filter/filter_fn.rs @@ -295,7 +295,7 @@ where metadata: &'static Metadata<'static>, ) -> Interest { // Because `self.enabled` takes a `Metadata` only (and no `Context` - // parameter), we can reasonably assume its results are cachable, and + // parameter), we can reasonably assume its results are cacheable, and // just return `Interest::always`/`Interest::never`. if (self.enabled)(metadata) { debug_assert!( diff --git a/tracing-subscriber/src/filter/layer_filters/mod.rs b/tracing-subscriber/src/filter/layer_filters/mod.rs index 040eb705f7..5f26625edc 100644 --- a/tracing-subscriber/src/filter/layer_filters/mod.rs +++ b/tracing-subscriber/src/filter/layer_filters/mod.rs @@ -721,7 +721,7 @@ where // // it would be cool if there was some wild rust reflection way of checking // if a trait impl has the default impl of a trait method or not, but that's - // almsot certainly impossible...right? + // almost certainly impossible...right? fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { let interest = self.filter.callsite_enabled(metadata); diff --git a/tracing-subscriber/src/filter/mod.rs b/tracing-subscriber/src/filter/mod.rs index 000a271951..045216721c 100644 --- a/tracing-subscriber/src/filter/mod.rs +++ b/tracing-subscriber/src/filter/mod.rs @@ -39,7 +39,7 @@ feature! { pub use self::directive::ParseError; } -/// Stub implementations of the per-layer-fitler detection functions for when the +/// Stub implementations of the per-layer-filter detection functions for when the /// `registry` feature is disabled. #[cfg(not(all(feature = "registry", feature = "std")))] mod has_plf_stubs { diff --git a/tracing-subscriber/src/fmt/format/mod.rs b/tracing-subscriber/src/fmt/format/mod.rs index 4e36ca0069..6fbae11296 100644 --- a/tracing-subscriber/src/fmt/format/mod.rs +++ b/tracing-subscriber/src/fmt/format/mod.rs @@ -1829,7 +1829,7 @@ pub(super) mod test { "^fake time tracing_subscriber::fmt::format::test: {}:[0-9]+: hello\n$", current_path() // if we're on Windows, the path might contain backslashes, which - // have to be escpaed before compiling the regex. + // have to be escaped before compiling the regex. .replace('\\', "\\\\") )) .unwrap(); diff --git a/tracing-subscriber/src/fmt/time/datetime.rs b/tracing-subscriber/src/fmt/time/datetime.rs index 2a1d3cfbb5..d08ed55873 100644 --- a/tracing-subscriber/src/fmt/time/datetime.rs +++ b/tracing-subscriber/src/fmt/time/datetime.rs @@ -387,7 +387,7 @@ mod tests { case("1901-12-13T20:45:52.000000Z", i32::MIN as i64, 0); case("1901-12-13T20:45:51.000000Z", i32::MIN as i64 - 1, 0); - // Skipping these tests on windows as std::time::SysteTime range is low + // Skipping these tests on windows as std::time::SystemTime range is low // on Windows compared with that of Unix which can cause the following // high date value tests to panic #[cfg(not(target_os = "windows"))] diff --git a/tracing-subscriber/src/layer/mod.rs b/tracing-subscriber/src/layer/mod.rs index 8543e2b08c..7b22cd3aa6 100644 --- a/tracing-subscriber/src/layer/mod.rs +++ b/tracing-subscriber/src/layer/mod.rs @@ -428,7 +428,7 @@ //! callsite). See [`Subscriber::register_callsite`] and //! [`tracing_core::callsite`] for a summary of how this behaves. //! - [`enabled`], once per emitted event (roughly: once per time that `event!` -//! or `span!` is *executed*), and only if `register_callsite` regesters an +//! or `span!` is *executed*), and only if `register_callsite` registers an //! [`Interest::sometimes`]. This is the main customization point to globally //! filter events based on their [`Metadata`]. If an event can be disabled //! based only on [`Metadata`], it should be, as this allows the construction @@ -764,7 +764,7 @@ where /// [`Subscriber`] has been set as the default, both the `Layer` and /// [`Subscriber`] are passed to this method _mutably_. This gives the /// `Layer` the opportunity to set any of its own fields with values - /// recieved by method calls on the [`Subscriber`]. + /// received by method calls on the [`Subscriber`]. /// /// For example, [`Filtered`] layers implement `on_layer` to call the /// [`Subscriber`]'s [`register_filter`] method, and store the returned @@ -1292,7 +1292,7 @@ feature! { ///
         /// Note: If a Filter will perform
         /// dynamic filtering that depends on the current context in which
-        /// a span or event was observered (e.g. only enabling an event when it
+        /// a span or event was observed (e.g. only enabling an event when it
         /// occurs within a particular span), it must return
         /// Interest::sometimes() from this method. If it returns
         /// Interest::always() or Interest::never(), the
@@ -1310,7 +1310,7 @@ feature! {
         /// other hand, when a `Filter` returns [`Interest::always()`][always] or
         /// [`Interest::never()`][never] for a callsite, _other_ [`Layer`]s may have
         /// differing interests in that callsite. If this is the case, the callsite
-        /// will recieve [`Interest::sometimes()`][sometimes], and the [`enabled`]
+        /// will receive [`Interest::sometimes()`][sometimes], and the [`enabled`]
         /// method will still be called for that callsite when it records a span or
         /// event.
         ///
diff --git a/tracing/CHANGELOG.md b/tracing/CHANGELOG.md
index db1668b16a..ffbd2925f9 100644
--- a/tracing/CHANGELOG.md
+++ b/tracing/CHANGELOG.md
@@ -651,7 +651,7 @@ this release!
   filtering, improving performance when a span or event is disabled by a
   `static_max_level_XXX` feature flag (#868) 
 - `LevelFilter` is now a re-export of the `tracing_core::LevelFilter` type, it
-  can now be used interchangably with the versions in `tracing-core` and
+  can now be used interchangeably with the versions in `tracing-core` and
   `tracing-subscriber` (#853)
 - Significant performance improvements when comparing `LevelFilter`s and
   `Level`s (#853)
diff --git a/tracing/README.md b/tracing/README.md
index c9ab85e104..b8758ef3ac 100644
--- a/tracing/README.md
+++ b/tracing/README.md
@@ -145,7 +145,7 @@ use tracing::{debug, error, info, span, warn, Level};
 
 // the `#[tracing::instrument]` attribute creates and enters a span
 // every time the instrumented function is called. The span is named after the
-// the function or method. Paramaters passed to the function are recorded as fields.
+// the function or method. Parameters passed to the function are recorded as fields.
 #[tracing::instrument]
 pub fn shave(yak: usize) -> Result<(), Box> {
     // this creates an event at the DEBUG level with two fields:
@@ -185,7 +185,7 @@ pub fn shave_all(yaks: usize) -> usize {
 
         if let Err(ref error) = res {
             // Like spans, events can also use the field initialization shorthand.
-            // In this instance, `yak` is the field being initalized.
+            // In this instance, `yak` is the field being initialized.
             error!(yak, error = error.as_ref(), "failed to shave yak!");
         } else {
             yaks_shaved += 1;
diff --git a/tracing/src/lib.rs b/tracing/src/lib.rs
index b3db75a64d..3425da591f 100644
--- a/tracing/src/lib.rs
+++ b/tracing/src/lib.rs
@@ -173,7 +173,7 @@
 //! For functions which don't have built-in tracing support and can't have
 //! the `#[instrument]` attribute applied (such as from an external crate),
 //! the [`Span` struct][`Span`] has a [`in_scope()` method][`in_scope`]
-//! which can be used to easily wrap synchonous code in a span.
+//! which can be used to easily wrap synchronous code in a span.
 //!
 //! For example:
 //! ```rust
diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs
index a3115ecf3e..a83229f223 100644
--- a/tracing/src/macros.rs
+++ b/tracing/src/macros.rs
@@ -3041,7 +3041,7 @@ macro_rules! fieldset {
         $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
     };
 
-    // Remainder is unparseable, but exists --- must be format args!
+    // Remainder is unparsable, but exists --- must be format args!
     (@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
         $crate::fieldset!(@ { "message", $($out),*, })
     };
diff --git a/tracing/tests/enabled.rs b/tracing/tests/enabled.rs
index 5a4596347e..e00b319713 100644
--- a/tracing/tests/enabled.rs
+++ b/tracing/tests/enabled.rs
@@ -43,7 +43,7 @@ fn span_and_event() {
 
     let _guard = tracing::subscriber::set_default(subscriber);
 
-    // Ensure that the `_event` and `_span` alternatives work corretly
+    // Ensure that the `_event` and `_span` alternatives work correctly
     assert!(!tracing::event_enabled!(Level::TRACE));
     assert!(tracing::event_enabled!(Level::DEBUG));
     assert!(tracing::span_enabled!(Level::TRACE));

From a46974d9884af6dd0750fa725543c5882ece99f8 Mon Sep 17 00:00:00 2001
From: Min Deng 
Date: Sun, 21 Jan 2024 02:40:06 +0800
Subject: [PATCH 06/21] docs: fix typo "synchonous" => "synchronous" (#2850)

Fix typo "synchonous" => "synchronous" in the crate level documentation.

This commit is empty, it's being backported so that we don't try and
baackport it later.

From c4aed1dcac8658b75ab1a21c8c8532fb0bd75875 Mon Sep 17 00:00:00 2001
From: Cijo Thomas 
Date: Wed, 24 Jan 2024 20:29:56 -0800
Subject: [PATCH 07/21] docs: Update README.md with correct link to tracing-etw
 (#2861)

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 033efdc3f7..d98bcc624f 100644
--- a/README.md
+++ b/README.md
@@ -436,7 +436,7 @@ please let us know!)
 [Tracy]: https://github.com/wolfpld/tracy
 [`tracing-elastic-apm`]: https://crates.io/crates/tracing-elastic-apm
 [Elastic APM]: https://www.elastic.co/apm
-[`tracing-etw`]: https://github.com/microsoft/tracing-etw
+[`tracing-etw`]: https://github.com/microsoft/rust_win_etw/tree/main/win_etw_tracing
 [ETW]: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing
 [`sentry-tracing`]: https://crates.io/crates/sentry-tracing
 [Sentry]: https://sentry.io/welcome/

From ce5b644c9714aa4ddb33d29f99a10483b3823e34 Mon Sep 17 00:00:00 2001
From: Alex Saveau 
Date: Thu, 25 Jan 2024 09:21:29 -0800
Subject: [PATCH 08/21] use const `thread_local`s when possible (#2838)

This results in a substantial performance improvement,
and is compatible with our MSRV.

Signed-off-by: Alex Saveau 
Co-authored-by: Eliza Weisman 
---
 .../examples/sloggish/sloggish_subscriber.rs  |  2 +-
 tracing-core/src/dispatcher.rs                | 10 +++--
 .../src/filter/layer_filters/mod.rs           | 44 ++++++++++++-------
 tracing-subscriber/src/registry/sharded.rs    |  6 +--
 4 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/examples/examples/sloggish/sloggish_subscriber.rs b/examples/examples/sloggish/sloggish_subscriber.rs
index 4cbc1385d8..fe42d3663a 100644
--- a/examples/examples/sloggish/sloggish_subscriber.rs
+++ b/examples/examples/sloggish/sloggish_subscriber.rs
@@ -38,7 +38,7 @@ pub struct CurrentSpanPerThread {
 impl CurrentSpanPerThread {
     pub fn new() -> Self {
         thread_local! {
-            static CURRENT: RefCell> = const { RefCell::new(vec![]) };
+            static CURRENT: RefCell> = const { RefCell::new(Vec::new()) };
         };
         Self { current: &CURRENT }
     }
diff --git a/tracing-core/src/dispatcher.rs b/tracing-core/src/dispatcher.rs
index deb56f7341..fc9f295844 100644
--- a/tracing-core/src/dispatcher.rs
+++ b/tracing-core/src/dispatcher.rs
@@ -183,10 +183,12 @@ enum Kind {
 
 #[cfg(feature = "std")]
 thread_local! {
-    static CURRENT_STATE: State = const { State {
-        default: RefCell::new(None),
-        can_enter: Cell::new(true),
-    } };
+    static CURRENT_STATE: State = const {
+        State {
+            default: RefCell::new(None),
+            can_enter: Cell::new(true),
+        }
+    };
 }
 
 static EXISTS: AtomicBool = AtomicBool::new(false);
diff --git a/tracing-subscriber/src/filter/layer_filters/mod.rs b/tracing-subscriber/src/filter/layer_filters/mod.rs
index 5f26625edc..f349d4ce6a 100644
--- a/tracing-subscriber/src/filter/layer_filters/mod.rs
+++ b/tracing-subscriber/src/filter/layer_filters/mod.rs
@@ -99,12 +99,18 @@ pub struct FilterId(u64);
 ///
 /// [`Registry`]: crate::Registry
 /// [`Filter`]: crate::layer::Filter
-#[derive(Default, Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq)]
 pub(crate) struct FilterMap {
     bits: u64,
 }
 
-/// The current state of `enabled` calls to per-layer filters on this
+impl FilterMap {
+    pub(crate) const fn new() -> Self {
+        Self { bits: 0 }
+    }
+}
+
+/// The current state of `enabled` calls to per-subscriber filters on this
 /// thread.
 ///
 /// When `Filtered::enabled` is called, the filter will set the bit
@@ -145,7 +151,7 @@ pub(crate) struct FilterState {
 
 /// Extra counters added to `FilterState` used only to make debug assertions.
 #[cfg(debug_assertions)]
-#[derive(Debug, Default)]
+#[derive(Debug)]
 struct DebugCounters {
     /// How many per-layer filters have participated in the current `enabled`
     /// call?
@@ -156,8 +162,18 @@ struct DebugCounters {
     in_interest_pass: Cell,
 }
 
+#[cfg(debug_assertions)]
+impl DebugCounters {
+    const fn new() -> Self {
+        Self {
+            in_filter_pass: Cell::new(0),
+            in_interest_pass: Cell::new(0),
+        }
+    }
+}
+
 thread_local! {
-    pub(crate) static FILTERING: FilterState = FilterState::new();
+    pub(crate) static FILTERING: FilterState = const { FilterState::new() };
 }
 
 /// Extension trait adding [combinators] for combining [`Filter`].
@@ -1080,13 +1096,13 @@ impl fmt::Binary for FilterMap {
 // === impl FilterState ===
 
 impl FilterState {
-    fn new() -> Self {
+    const fn new() -> Self {
         Self {
-            enabled: Cell::new(FilterMap::default()),
+            enabled: Cell::new(FilterMap::new()),
             interest: RefCell::new(None),
 
             #[cfg(debug_assertions)]
-            counters: DebugCounters::default(),
+            counters: DebugCounters::new(),
         }
     }
 
@@ -1095,7 +1111,7 @@ impl FilterState {
         {
             let in_current_pass = self.counters.in_filter_pass.get();
             if in_current_pass == 0 {
-                debug_assert_eq!(self.enabled.get(), FilterMap::default());
+                debug_assert_eq!(self.enabled.get(), FilterMap::new());
             }
             self.counters.in_filter_pass.set(in_current_pass + 1);
             debug_assert_eq!(
@@ -1140,7 +1156,7 @@ impl FilterState {
                 #[cfg(debug_assertions)]
                 {
                     if this.counters.in_filter_pass.get() == 0 {
-                        debug_assert_eq!(this.enabled.get(), FilterMap::default());
+                        debug_assert_eq!(this.enabled.get(), FilterMap::new());
                     }
 
                     // Nothing enabled this event, we won't tick back down the
@@ -1177,7 +1193,7 @@ impl FilterState {
         {
             let in_current_pass = self.counters.in_filter_pass.get();
             if in_current_pass <= 1 {
-                debug_assert_eq!(self.enabled.get(), FilterMap::default());
+                debug_assert_eq!(self.enabled.get(), FilterMap::new());
             }
             self.counters
                 .in_filter_pass
@@ -1207,7 +1223,7 @@ impl FilterState {
         // a panic and the thread-local has been torn down, that's fine, just
         // ignore it ratehr than panicking.
         let _ = FILTERING.try_with(|filtering| {
-            filtering.enabled.set(FilterMap::default());
+            filtering.enabled.set(FilterMap::new());
 
             #[cfg(debug_assertions)]
             filtering.counters.in_filter_pass.set(0);
@@ -1232,10 +1248,8 @@ impl FilterState {
     pub(crate) fn filter_map(&self) -> FilterMap {
         let map = self.enabled.get();
         #[cfg(debug_assertions)]
-        {
-            if self.counters.in_filter_pass.get() == 0 {
-                debug_assert_eq!(map, FilterMap::default());
-            }
+        if self.counters.in_filter_pass.get() == 0 {
+            debug_assert_eq!(map, FilterMap::new());
         }
 
         map
diff --git a/tracing-subscriber/src/registry/sharded.rs b/tracing-subscriber/src/registry/sharded.rs
index 17a3775cab..7d631b08e6 100644
--- a/tracing-subscriber/src/registry/sharded.rs
+++ b/tracing-subscriber/src/registry/sharded.rs
@@ -255,7 +255,7 @@ impl Subscriber for Registry {
                 data.filter_map = crate::filter::FILTERING.with(|filtering| filtering.filter_map());
                 #[cfg(debug_assertions)]
                 {
-                    if data.filter_map != FilterMap::default() {
+                    if data.filter_map != FilterMap::new() {
                         debug_assert!(self.has_per_layer_filters());
                     }
                 }
@@ -481,7 +481,7 @@ impl Default for DataInner {
         };
 
         Self {
-            filter_map: FilterMap::default(),
+            filter_map: FilterMap::new(),
             metadata: &NULL_METADATA,
             parent: None,
             ref_count: AtomicUsize::new(0),
@@ -526,7 +526,7 @@ impl Clear for DataInner {
             })
             .clear();
 
-        self.filter_map = FilterMap::default();
+        self.filter_map = FilterMap::new();
     }
 }
 

From 92633c81ccc7d857378f1a3e3d939f9217aec15a Mon Sep 17 00:00:00 2001
From: Tobias Bieniek 
Date: Thu, 15 Feb 2024 22:54:04 +0100
Subject: [PATCH 09/21] macros: Fix missing field prefixes (#2878)

## Motivation

In the simple macro cases with e.g. only "name" or only "target" these
prefixes exist, but for the more complicated cases like "name + target"
the prefixes were not piped through and silently ignored. This led to
the compiler complaining about `Value` not being implemented despite the
usage of the `?` or `%` prefixes:

Bildschirmfoto 2024-02-14 um 12 38 00


## Solution

This change adds the missing prefixes to the `$($k)` tokens, like they
already exist for the simple cases mentioned above.
---
 tracing/src/macros.rs   | 80 ++++++++++++++++++++---------------------
 tracing/tests/macros.rs | 75 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+), 40 deletions(-)

diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs
index a83229f223..7876aed383 100644
--- a/tracing/src/macros.rs
+++ b/tracing/src/macros.rs
@@ -1309,10 +1309,10 @@ macro_rules! trace {
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1326,10 +1326,10 @@ macro_rules! trace {
         $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+)
@@ -1343,10 +1343,10 @@ macro_rules! trace {
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1360,10 +1360,10 @@ macro_rules! trace {
         $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1586,10 +1586,10 @@ macro_rules! debug {
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1603,10 +1603,10 @@ macro_rules! debug {
         $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1620,10 +1620,10 @@ macro_rules! debug {
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1637,10 +1637,10 @@ macro_rules! debug {
         $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1874,10 +1874,10 @@ macro_rules! info {
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -1891,10 +1891,10 @@ macro_rules! info {
         $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+)
@@ -1908,10 +1908,10 @@ macro_rules! info {
         $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -1925,10 +1925,10 @@ macro_rules! info {
         $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -2155,10 +2155,10 @@ macro_rules! warn {
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2172,10 +2172,10 @@ macro_rules! warn {
         $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+)
@@ -2189,10 +2189,10 @@ macro_rules! warn {
         $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2206,10 +2206,10 @@ macro_rules! warn {
         $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2432,10 +2432,10 @@ macro_rules! error {
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
@@ -2449,10 +2449,10 @@ macro_rules! error {
         $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+)
@@ -2466,10 +2466,10 @@ macro_rules! error {
         $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
@@ -2483,10 +2483,10 @@ macro_rules! error {
         $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
diff --git a/tracing/tests/macros.rs b/tracing/tests/macros.rs
index b6e568f4a6..e9966a5464 100644
--- a/tracing/tests/macros.rs
+++ b/tracing/tests/macros.rs
@@ -10,6 +10,16 @@ use tracing::{
     span, span_enabled, trace, trace_span, warn, warn_span, Level,
 };
 
+/// A type that implements `Display` and `Debug`, but not `Value`.
+#[derive(Debug)]
+struct DisplayDebug;
+
+impl ::std::fmt::Display for DisplayDebug {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::std::write!(f, "Foo")
+    }
+}
+
 // Tests that macros work across various invocation syntax.
 //
 // These are quite repetitive, and _could_ be generated by a macro. However,
@@ -581,6 +591,19 @@ fn trace() {
     trace!(target: "foo_events", ?foo, true, "message");
     trace!(target: "foo_events", %foo, true, "message");
     trace!(target: "foo_events", foo, true, "message");
+    let foo = DisplayDebug;
+    trace!(?foo);
+    trace!(%foo);
+    trace!(name: "foo", ?foo);
+    trace!(name: "foo", %foo);
+    trace!(name: "foo", ?foo, true, "message");
+    trace!(name: "foo", %foo, true, "message");
+    trace!(target: "foo_events", ?foo);
+    trace!(target: "foo_events", %foo);
+    trace!(target: "foo_events", ?foo, true, "message");
+    trace!(target: "foo_events", %foo, true, "message");
+    trace!(name: "foo", target: "foo_events", ?foo, true, "message");
+    trace!(name: "foo", target: "foo_events", %foo, true, "message");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -625,6 +648,19 @@ fn debug() {
     debug!(target: "foo_events", ?foo, true, "message");
     debug!(target: "foo_events", %foo, true, "message");
     debug!(target: "foo_events", foo, true, "message");
+    let foo = DisplayDebug;
+    debug!(?foo);
+    debug!(%foo);
+    debug!(name: "foo", ?foo);
+    debug!(name: "foo", %foo);
+    debug!(name: "foo", ?foo, true, "message");
+    debug!(name: "foo", %foo, true, "message");
+    debug!(target: "foo_events", ?foo);
+    debug!(target: "foo_events", %foo);
+    debug!(target: "foo_events", ?foo, true, "message");
+    debug!(target: "foo_events", %foo, true, "message");
+    debug!(name: "foo", target: "foo_events", ?foo, true, "message");
+    debug!(name: "foo", target: "foo_events", %foo, true, "message");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -669,6 +705,19 @@ fn info() {
     info!(target: "foo_events", ?foo, true, "message");
     info!(target: "foo_events", %foo, true, "message");
     info!(target: "foo_events", foo, true, "message");
+    let foo = DisplayDebug;
+    info!(?foo);
+    info!(%foo);
+    info!(name: "foo", ?foo);
+    info!(name: "foo", %foo);
+    info!(name: "foo", ?foo, true, "message");
+    info!(name: "foo", %foo, true, "message");
+    info!(target: "foo_events", ?foo);
+    info!(target: "foo_events", %foo);
+    info!(target: "foo_events", ?foo, true, "message");
+    info!(target: "foo_events", %foo, true, "message");
+    info!(name: "foo", target: "foo_events", ?foo, true, "message");
+    info!(name: "foo", target: "foo_events", %foo, true, "message");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -713,6 +762,19 @@ fn warn() {
     warn!(target: "foo_events", ?foo, true, "message");
     warn!(target: "foo_events", %foo, true, "message");
     warn!(target: "foo_events", foo, true, "message");
+    let foo = DisplayDebug;
+    warn!(?foo);
+    warn!(%foo);
+    warn!(name: "foo", ?foo);
+    warn!(name: "foo", %foo);
+    warn!(name: "foo", ?foo, true, "message");
+    warn!(name: "foo", %foo, true, "message");
+    warn!(target: "foo_events", ?foo);
+    warn!(target: "foo_events", %foo);
+    warn!(target: "foo_events", ?foo, true, "message");
+    warn!(target: "foo_events", %foo, true, "message");
+    warn!(name: "foo", target: "foo_events", ?foo, true, "message");
+    warn!(name: "foo", target: "foo_events", %foo, true, "message");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -757,6 +819,19 @@ fn error() {
     error!(target: "foo_events", ?foo, true, "message");
     error!(target: "foo_events", %foo, true, "message");
     error!(target: "foo_events", foo, true, "message");
+    let foo = DisplayDebug;
+    error!(?foo);
+    error!(%foo);
+    error!(name: "foo", ?foo);
+    error!(name: "foo", %foo);
+    error!(name: "foo", ?foo, true, "message");
+    error!(name: "foo", %foo, true, "message");
+    error!(target: "foo_events", ?foo);
+    error!(target: "foo_events", %foo);
+    error!(target: "foo_events", ?foo, true, "message");
+    error!(target: "foo_events", %foo, true, "message");
+    error!(name: "foo", target: "foo_events", ?foo, true, "message");
+    error!(name: "foo", target: "foo_events", %foo, true, "message");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]

From 83136ef83fcdf7b95e2656090b1e76da5ff939ad Mon Sep 17 00:00:00 2001
From: Tobias Bieniek 
Date: Fri, 16 Feb 2024 20:48:38 +0100
Subject: [PATCH 10/21] macros: Fix non-simple macro usage without message
 (#2879)

If something like `warn!(?foo)` and `warn!(name: "foo", ?foo)` works, then `warn!(name: "foo", target: "foo_events", ?foo)` should arguably also work. Before this change the more complicated variants of the macros however required a message argument, due to the usage of the `+` specifier in the macro definitions. This commit changes the `+` (1 or more) to `*` (0 or more), which matches how the `field` tokens are used in the simpler variants of the macro.
---
 tracing/src/macros.rs   | 240 ++++++++++++++++++++--------------------
 tracing/tests/macros.rs |  15 +++
 2 files changed, 135 insertions(+), 120 deletions(-)

diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs
index 7876aed383..d359775424 100644
--- a/tracing/src/macros.rs
+++ b/tracing/src/macros.rs
@@ -1305,14 +1305,14 @@ macro_rules! trace {
     (name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1322,14 +1322,14 @@ macro_rules! trace {
     (name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+)
@@ -1339,14 +1339,14 @@ macro_rules! trace {
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
     );
-    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1356,14 +1356,14 @@ macro_rules! trace {
     (name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
@@ -1582,14 +1582,14 @@ macro_rules! debug {
     (name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1599,14 +1599,14 @@ macro_rules! debug {
     (name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1616,14 +1616,14 @@ macro_rules! debug {
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
     );
-    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1633,14 +1633,14 @@ macro_rules! debug {
     (name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
@@ -1870,14 +1870,14 @@ macro_rules! info {
     (name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -1887,14 +1887,14 @@ macro_rules! info {
     (name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+)
@@ -1904,14 +1904,14 @@ macro_rules! info {
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
     );
-    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -1921,14 +1921,14 @@ macro_rules! info {
     (name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
@@ -2151,14 +2151,14 @@ macro_rules! warn {
     (name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2168,14 +2168,14 @@ macro_rules! warn {
     (name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+)
@@ -2185,14 +2185,14 @@ macro_rules! warn {
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
     );
-    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2202,14 +2202,14 @@ macro_rules! warn {
     (name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
@@ -2428,14 +2428,14 @@ macro_rules! error {
     (name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
@@ -2445,14 +2445,14 @@ macro_rules! error {
     (name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)+ })
+    (name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
     );
     (name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+)
@@ -2462,14 +2462,14 @@ macro_rules! error {
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
     );
-    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
     );
-    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
+    (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
     );
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
@@ -2479,14 +2479,14 @@ macro_rules! error {
     (name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
     );
-    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
     );
-    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
-        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)+ })
+    (name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
     );
     (name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
diff --git a/tracing/tests/macros.rs b/tracing/tests/macros.rs
index e9966a5464..8d58bf6107 100644
--- a/tracing/tests/macros.rs
+++ b/tracing/tests/macros.rs
@@ -591,6 +591,9 @@ fn trace() {
     trace!(target: "foo_events", ?foo, true, "message");
     trace!(target: "foo_events", %foo, true, "message");
     trace!(target: "foo_events", foo, true, "message");
+    trace!(name: "foo", target: "foo_events", ?foo);
+    trace!(name: "foo", target: "foo_events", %foo);
+    trace!(name: "foo", target: "foo_events", foo);
     let foo = DisplayDebug;
     trace!(?foo);
     trace!(%foo);
@@ -648,6 +651,9 @@ fn debug() {
     debug!(target: "foo_events", ?foo, true, "message");
     debug!(target: "foo_events", %foo, true, "message");
     debug!(target: "foo_events", foo, true, "message");
+    debug!(name: "foo", target: "foo_events", ?foo);
+    debug!(name: "foo", target: "foo_events", %foo);
+    debug!(name: "foo", target: "foo_events", foo);
     let foo = DisplayDebug;
     debug!(?foo);
     debug!(%foo);
@@ -705,6 +711,9 @@ fn info() {
     info!(target: "foo_events", ?foo, true, "message");
     info!(target: "foo_events", %foo, true, "message");
     info!(target: "foo_events", foo, true, "message");
+    info!(name: "foo", target: "foo_events", ?foo);
+    info!(name: "foo", target: "foo_events", %foo);
+    info!(name: "foo", target: "foo_events", foo);
     let foo = DisplayDebug;
     info!(?foo);
     info!(%foo);
@@ -762,6 +771,9 @@ fn warn() {
     warn!(target: "foo_events", ?foo, true, "message");
     warn!(target: "foo_events", %foo, true, "message");
     warn!(target: "foo_events", foo, true, "message");
+    warn!(name: "foo", target: "foo_events", ?foo);
+    warn!(name: "foo", target: "foo_events", %foo);
+    warn!(name: "foo", target: "foo_events", foo);
     let foo = DisplayDebug;
     warn!(?foo);
     warn!(%foo);
@@ -819,6 +831,9 @@ fn error() {
     error!(target: "foo_events", ?foo, true, "message");
     error!(target: "foo_events", %foo, true, "message");
     error!(target: "foo_events", foo, true, "message");
+    error!(name: "foo", target: "foo_events", ?foo);
+    error!(name: "foo", target: "foo_events", %foo);
+    error!(name: "foo", target: "foo_events", foo);
     let foo = DisplayDebug;
     error!(?foo);
     error!(%foo);

From 7bb5bb25db9de55f7eda7165999a702265244452 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Ml=C3=A1dek?= 
Date: Fri, 1 Mar 2024 21:59:00 +0100
Subject: [PATCH 11/21] tracing: fix event macros with constant field names in
 the first position (#2883)

## Motivation

Const argumetns in `level!` macros do not work when in the first
position.

This also seems to have fixed #2748 where literals for fields names like
`info!("foo" = 2)` could not be used outside the `event!` macro.


Fixes #2837
Fixes #2738

## Solution

Previsously, `level!($(args:tt))` was forwarded to `event!(target: ...,
level: ..., { $(args:tt) })` but the added curly braces seem to have
prevented the `event` macro from correctly understanding the arguments
and it tried to pass them to `format!`.

With this change there may have some performance impact when expanding
the macros in most cases where the braces could have been added as it
will take one more step.

These are the two relevant `event!` blocks I believe, the new tests used
to expand to the first one (with empty fields), now they expand to the
latter:
```
    (target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
        $crate::event!(
            target: $target,
            $lvl,
            { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
        )
    );
    (target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
        $crate::event!(target: $target, $lvl, { $($arg)+ })
    );
```
---
 tracing/src/macros.rs   |  5 ----
 tracing/tests/event.rs  | 54 +++++++++++++++++++++++++++++++++++++++++
 tracing/tests/macros.rs | 32 +++++++++++++++++++++++-
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs
index d359775424..5e9f65d075 100644
--- a/tracing/src/macros.rs
+++ b/tracing/src/macros.rs
@@ -1547,7 +1547,6 @@ macro_rules! trace {
         $crate::event!(
             target: module_path!(),
             $crate::Level::TRACE,
-            {},
             $($arg)+
         )
     );
@@ -1824,7 +1823,6 @@ macro_rules! debug {
         $crate::event!(
             target: module_path!(),
             $crate::Level::DEBUG,
-            {},
             $($arg)+
         )
     );
@@ -2112,7 +2110,6 @@ macro_rules! info {
         $crate::event!(
             target: module_path!(),
             $crate::Level::INFO,
-            {},
             $($arg)+
         )
     );
@@ -2393,7 +2390,6 @@ macro_rules! warn {
         $crate::event!(
             target: module_path!(),
             $crate::Level::WARN,
-            {},
             $($arg)+
         )
     );
@@ -2670,7 +2666,6 @@ macro_rules! error {
         $crate::event!(
             target: module_path!(),
             $crate::Level::ERROR,
-            {},
             $($arg)+
         )
     );
diff --git a/tracing/tests/event.rs b/tracing/tests/event.rs
index 175b21bedf..55e9b81bc4 100644
--- a/tracing/tests/event.rs
+++ b/tracing/tests/event.rs
@@ -525,6 +525,12 @@ fn constant_field_name() {
         )
     };
     let (subscriber, handle) = subscriber::mock()
+        .event(expect_event())
+        .event(expect_event())
+        .event(expect_event())
+        .event(expect_event())
+        .event(expect_event())
+        .event(expect_event())
         .event(expect_event())
         .event(expect_event())
         .only()
@@ -548,6 +554,54 @@ fn constant_field_name() {
             },
             "quux"
         );
+        tracing::info!(
+            { std::convert::identity(FOO) } = "bar",
+            { "constant string" } = "also works",
+            foo.bar = "baz",
+            "quux"
+        );
+        tracing::info!(
+            {
+                { std::convert::identity(FOO) } = "bar",
+                { "constant string" } = "also works",
+                foo.bar = "baz",
+            },
+            "quux"
+        );
+        tracing::event!(
+            Level::INFO,
+            { std::convert::identity(FOO) } = "bar",
+            { "constant string" } = "also works",
+            foo.bar = "baz",
+            "{}",
+            "quux"
+        );
+        tracing::event!(
+            Level::INFO,
+            {
+                { std::convert::identity(FOO) } = "bar",
+                { "constant string" } = "also works",
+                foo.bar = "baz",
+            },
+            "{}",
+            "quux"
+        );
+        tracing::info!(
+            { std::convert::identity(FOO) } = "bar",
+            { "constant string" } = "also works",
+            foo.bar = "baz",
+            "{}",
+            "quux"
+        );
+        tracing::info!(
+            {
+                { std::convert::identity(FOO) } = "bar",
+                { "constant string" } = "also works",
+                foo.bar = "baz",
+            },
+            "{}",
+            "quux"
+        );
     });
 
     handle.assert_finished();
diff --git a/tracing/tests/macros.rs b/tracing/tests/macros.rs
index 8d58bf6107..a072389e24 100644
--- a/tracing/tests/macros.rs
+++ b/tracing/tests/macros.rs
@@ -555,12 +555,15 @@ fn trace() {
     trace!(foo = ?3, bar.baz = %2, quux = false);
     trace!(foo = 3, bar.baz = 2, quux = false);
     trace!(foo = 3, bar.baz = 3,);
+    trace!("foo" = 3, bar.baz = 3,);
+    trace!(foo = 3, "bar.baz" = 3,);
     trace!("foo");
     trace!("foo: {}", 3);
     trace!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
     trace!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
     trace!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
     trace!({ foo = 3, bar.baz = 80 }, "quux");
+    trace!({ "foo" = 3, "bar.baz" = 80 }, "quux");
     trace!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
     trace!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     trace!({ foo = 2, bar.baz = 78 }, "quux");
@@ -579,6 +582,9 @@ fn trace() {
     trace!(?foo);
     trace!(%foo);
     trace!(foo);
+    trace!("foo" = ?foo);
+    trace!("foo" = %foo);
+    trace!("foo" = foo);
     trace!(name: "foo", ?foo);
     trace!(name: "foo", %foo);
     trace!(name: "foo", foo);
@@ -615,12 +621,15 @@ fn debug() {
     debug!(foo = ?3, bar.baz = %2, quux = false);
     debug!(foo = 3, bar.baz = 2, quux = false);
     debug!(foo = 3, bar.baz = 3,);
+    debug!("foo" = 3, bar.baz = 3,);
+    debug!(foo = 3, "bar.baz" = 3,);
     debug!("foo");
     debug!("foo: {}", 3);
     debug!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
     debug!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
     debug!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
     debug!({ foo = 3, bar.baz = 80 }, "quux");
+    debug!({ "foo" = 3, "bar.baz" = 80 }, "quux");
     debug!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
     debug!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     debug!({ foo = 2, bar.baz = 78 }, "quux");
@@ -639,6 +648,9 @@ fn debug() {
     debug!(?foo);
     debug!(%foo);
     debug!(foo);
+    debug!("foo" = ?foo);
+    debug!("foo" = %foo);
+    debug!("foo" = foo);
     debug!(name: "foo", ?foo);
     debug!(name: "foo", %foo);
     debug!(name: "foo", foo);
@@ -675,12 +687,15 @@ fn info() {
     info!(foo = ?3, bar.baz = %2, quux = false);
     info!(foo = 3, bar.baz = 2, quux = false);
     info!(foo = 3, bar.baz = 3,);
+    info!("foo" = 3, bar.baz = 3,);
+    info!(foo = 3, "bar.baz" = 3,);
     info!("foo");
     info!("foo: {}", 3);
     info!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
     info!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
     info!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
     info!({ foo = 3, bar.baz = 80 }, "quux");
+    info!({ "foo" = 3, "bar.baz" = 80 }, "quux");
     info!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
     info!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     info!({ foo = 2, bar.baz = 78 }, "quux");
@@ -699,6 +714,9 @@ fn info() {
     info!(?foo);
     info!(%foo);
     info!(foo);
+    info!("foo" = ?foo);
+    info!("foo" = %foo);
+    info!("foo" = foo);
     info!(name: "foo", ?foo);
     info!(name: "foo", %foo);
     info!(name: "foo", foo);
@@ -735,12 +753,15 @@ fn warn() {
     warn!(foo = ?3, bar.baz = %2, quux = false);
     warn!(foo = 3, bar.baz = 2, quux = false);
     warn!(foo = 3, bar.baz = 3,);
+    warn!("foo" = 3, bar.baz = 3,);
+    warn!(foo = 3, "bar.baz" = 3,);
     warn!("foo");
     warn!("foo: {}", 3);
     warn!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
     warn!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
     warn!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
     warn!({ foo = 3, bar.baz = 80 }, "quux");
+    warn!({ "foo" = 3, "bar.baz" = 80 }, "quux");
     warn!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
     warn!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     warn!({ foo = 2, bar.baz = 78 }, "quux");
@@ -759,6 +780,9 @@ fn warn() {
     warn!(?foo);
     warn!(%foo);
     warn!(foo);
+    warn!("foo" = ?foo);
+    warn!("foo" = %foo);
+    warn!("foo" = foo);
     warn!(name: "foo", ?foo);
     warn!(name: "foo", %foo);
     warn!(name: "foo", foo);
@@ -795,15 +819,18 @@ fn error() {
     error!(foo = ?3, bar.baz = %2, quux = false);
     error!(foo = 3, bar.baz = 2, quux = false);
     error!(foo = 3, bar.baz = 3,);
+    error!("foo" = 3, bar.baz = 3,);
+    error!(foo = 3, "bar.baz" = 3,);
     error!("foo");
     error!("foo: {}", 3);
     error!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
     error!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
     error!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
     error!({ foo = 3, bar.baz = 80 }, "quux");
+    error!({ "foo" = 3, "bar.baz" = 80 }, "quux");
     error!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
     error!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    error!({ foo = 2, bar.baz = 78, }, "quux");
+    error!({ foo = 2, bar.baz = 78 }, "quux");
     error!({ foo = ?2, bar.baz = %78 }, "quux");
     error!(name: "foo", foo = 3, bar.baz = 2, quux = false);
     error!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
@@ -819,6 +846,9 @@ fn error() {
     error!(?foo);
     error!(%foo);
     error!(foo);
+    error!("foo" = ?foo);
+    error!("foo" = %foo);
+    error!("foo" = foo);
     error!(name: "foo", ?foo);
     error!(name: "foo", %foo);
     error!(name: "foo", foo);

From 93f430c0bda08a7d6f16618c275d5e9253164f69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Ml=C3=A1dek?= 
Date: Fri, 3 May 2024 19:17:38 +0200
Subject: [PATCH 12/21] tracing: allow `&[u8]` to be recorded as event/span
 field (#2954)

Users may want to pass data to `Subscribe`s which is not valid UTF-8. Currently, it would have to be encoded into `&str` to be passed as a field value.

This branch adds a `record_bytes` method to `Visit`. It has an implementation falling back to `record_debug` so it is not be a breaking change.

`JsonVisitor` got an overridden implementation as it should not use `Debug` output and encode it as a string, but rather store the bytes as an array.

`PrettyVisitor` go an overridden implementation to make the output more pretty.

Co-authored-by: Eliza Weisman 
---
 tracing-core/src/field.rs                 | 54 ++++++++++++++++++++++-
 tracing-subscriber/src/fmt/format/json.rs | 15 ++++++-
 2 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/tracing-core/src/field.rs b/tracing-core/src/field.rs
index 2267407164..52d1dcf8a4 100644
--- a/tracing-core/src/field.rs
+++ b/tracing-core/src/field.rs
@@ -112,7 +112,7 @@
 use crate::callsite;
 use crate::stdlib::{
     borrow::Borrow,
-    fmt,
+    fmt::{self, Write},
     hash::{Hash, Hasher},
     num,
     ops::Range,
@@ -308,6 +308,11 @@ pub trait Visit {
         self.record_debug(field, &value)
     }
 
+    /// Visit a byte slice.
+    fn record_bytes(&mut self, field: &Field, value: &[u8]) {
+        self.record_debug(field, &HexBytes(value))
+    }
+
     /// Records a type implementing `Error`.
     ///
     /// 
@@ -380,6 +385,26 @@ where t.as_value() } +struct HexBytes<'a>(&'a [u8]); + +impl<'a> fmt::Debug for HexBytes<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_char('[')?; + + let mut bytes = self.0.iter(); + + if let Some(byte) = bytes.next() { + f.write_fmt(format_args!("{byte:02x}"))?; + } + + for byte in bytes { + f.write_fmt(format_args!(" {byte:02x}"))?; + } + + f.write_char(']') + } +} + // ===== impl Visit ===== impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> { @@ -540,6 +565,14 @@ impl Value for str { } } +impl crate::sealed::Sealed for [u8] {} + +impl Value for [u8] { + fn record(&self, key: &Field, visitor: &mut dyn Visit) { + visitor.record_bytes(key, self) + } +} + #[cfg(feature = "std")] impl crate::sealed::Sealed for dyn std::error::Error + 'static {} @@ -1249,4 +1282,23 @@ mod test { }); assert_eq!(result, format!("{}", err)); } + + #[test] + fn record_bytes() { + let fields = TEST_META_1.fields(); + let first = &b"abc"[..]; + let second: &[u8] = &[192, 255, 238]; + let values = &[ + (&fields.field("foo").unwrap(), Some(&first as &dyn Value)), + (&fields.field("bar").unwrap(), Some(&" " as &dyn Value)), + (&fields.field("baz").unwrap(), Some(&second as &dyn Value)), + ]; + let valueset = fields.value_set(values); + let mut result = String::new(); + valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| { + use core::fmt::Write; + write!(&mut result, "{:?}", value).unwrap(); + }); + assert_eq!(result, format!("{}", r#"[61 62 63]" "[c0 ff ee]"#)); + } } diff --git a/tracing-subscriber/src/fmt/format/json.rs b/tracing-subscriber/src/fmt/format/json.rs index 7799abb6e0..c8cb84a472 100644 --- a/tracing-subscriber/src/fmt/format/json.rs +++ b/tracing-subscriber/src/fmt/format/json.rs @@ -525,6 +525,11 @@ impl<'a> field::Visit for JsonVisitor<'a> { .insert(field.name(), serde_json::Value::from(value)); } + fn record_bytes(&mut self, field: &Field, value: &[u8]) { + self.values + .insert(field.name(), serde_json::Value::from(value)); + } + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { match field.name() { // Skip fields that are actually log metadata that have already been handled @@ -564,13 +569,19 @@ mod test { #[test] fn json() { let expected = - "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n"; + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3,\"slice\":[97,98,99]},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3,\"slice\":[97,98,99]}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n"; let subscriber = subscriber() .flatten_event(false) .with_current_span(true) .with_span_list(true); test_json(expected, subscriber, || { - let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let span = tracing::span!( + tracing::Level::INFO, + "json_span", + answer = 42, + number = 3, + slice = &b"abc"[..] + ); let _guard = span.enter(); tracing::info!("some json test"); }); From e9d34682052fa9c80f4f99645993819cdc981eba Mon Sep 17 00:00:00 2001 From: Logan Praneis Date: Sat, 25 May 2024 12:53:42 -0500 Subject: [PATCH 13/21] subscriber: add `set_span_events` to `fmt::Subscriber` (#2962) --- tracing-subscriber/src/fmt/fmt_layer.rs | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tracing-subscriber/src/fmt/fmt_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index 54c84e422c..399b0eba27 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -241,6 +241,27 @@ impl Layer { self.is_ansi = ansi; } + /// Modifies how synthesized events are emitted at points in the [span + /// lifecycle][lifecycle]. + /// + /// See [`Self::with_span_events`] for documentation on the [`FmtSpan`] + /// + /// This method is primarily expected to be used with the + /// [`reload::Handle::modify`](crate::reload::Handle::modify) method + /// + /// Note that using this method modifies the span configuration instantly and does not take into + /// account any current spans. If the previous configuration was set to capture + /// `FmtSpan::ALL`, for example, using this method to change to `FmtSpan::NONE` will cause an + /// exit event for currently entered events not to be formatted + /// + /// [lifecycle]: mod@tracing::span#the-span-lifecycle + pub fn set_span_events(&mut self, kind: FmtSpan) { + self.fmt_span = format::FmtSpanConfig { + kind, + fmt_timing: self.fmt_span.fmt_timing, + } + } + /// Configures the layer to support [`libtest`'s output capturing][capturing] when used in /// unit tests. /// @@ -1587,4 +1608,52 @@ mod test { // dropping `_saved_no_color` will restore the previous value of // `NO_COLOR`. } + + // Validates that span event configuration can be modified with a reload handle + #[test] + fn modify_span_events() { + let make_writer = MockMakeWriter::default(); + + let inner_layer = fmt::Layer::default() + .with_writer(make_writer.clone()) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime) + .with_span_events(FmtSpan::ACTIVE); + + let (reloadable_layer, reload_handle) = + crate::reload::Layer::new(inner_layer); + let reload = reloadable_layer.with_subscriber(Registry::default()); + + with_default(reload, || { + { + let span1 = tracing::info_span!("span1", x = 42); + let _e = span1.enter(); + } + + let _ = reload_handle.modify(|s| s.set_span_events(FmtSpan::NONE)); + + // this span should not be logged at all! + { + let span2 = tracing::info_span!("span2", x = 100); + let _e = span2.enter(); + } + + { + let span3 = tracing::info_span!("span3", x = 42); + let _e = span3.enter(); + + // The span config was modified after span3 was already entered. + // We should only see an exit + let _ = reload_handle.modify(|s| s.set_span_events(FmtSpan::ACTIVE)); + } + }); + let actual = sanitize_timings(make_writer.get_string()); + assert_eq!( + "fake time span1{x=42}: tracing_subscriber::fmt::fmt_layer::test: enter\n\ + fake time span1{x=42}: tracing_subscriber::fmt::fmt_layer::test: exit\n\ + fake time span3{x=42}: tracing_subscriber::fmt::fmt_layer::test: exit\n", + actual.as_str() + ); + } } From d921d5f22704842e2c9a72222529714bd9f059dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Sat, 25 May 2024 11:08:34 -0700 Subject: [PATCH 14/21] tracing-attributes: support const values for `target` and `name` (#2941) Fixes #2960 Co-authored-by: Matthijs Brobbel Co-authored-by: Hayden Stainsby Co-authored-by: Eliza Weisman --- tracing-attributes/src/attr.rs | 32 ++++++++++-- tracing-attributes/tests/instrument.rs | 72 ++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/tracing-attributes/src/attr.rs b/tracing-attributes/src/attr.rs index 8b4526164b..12525ec9e6 100644 --- a/tracing-attributes/src/attr.rs +++ b/tracing-attributes/src/attr.rs @@ -17,8 +17,8 @@ pub(crate) struct EventArgs { #[derive(Clone, Default, Debug)] pub(crate) struct InstrumentArgs { level: Option, - pub(crate) name: Option, - target: Option, + pub(crate) name: Option, + target: Option, pub(crate) parent: Option, pub(crate) follows_from: Option, pub(crate) skips: HashSet, @@ -87,6 +87,8 @@ impl Parse for InstrumentArgs { // XXX: apparently we support names as either named args with an // sign, _or_ as unnamed string literals. That's weird, but // changing it is apparently breaking. + // This also means that when using idents for name, it must be via + // a named arg, i.e. `#[instrument(name = SOME_IDENT)]`. if args.name.is_some() { return Err(input.error("expected only a single `name` argument")); } @@ -211,8 +213,32 @@ impl Parse for EventArgs { } } +#[derive(Debug, Clone)] +pub(super) enum LitStrOrIdent { + LitStr(LitStr), + Ident(Ident), +} + +impl ToTokens for LitStrOrIdent { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + LitStrOrIdent::LitStr(target) => target.to_tokens(tokens), + LitStrOrIdent::Ident(ident) => ident.to_tokens(tokens), + } + } +} + +impl Parse for LitStrOrIdent { + fn parse(input: ParseStream<'_>) -> syn::Result { + input + .parse::() + .map(LitStrOrIdent::LitStr) + .or_else(|_| input.parse::().map(LitStrOrIdent::Ident)) + } +} + struct StrArg { - value: LitStr, + value: LitStrOrIdent, _p: std::marker::PhantomData, } diff --git a/tracing-attributes/tests/instrument.rs b/tracing-attributes/tests/instrument.rs index d01df0c313..402be8572a 100644 --- a/tracing-attributes/tests/instrument.rs +++ b/tracing-attributes/tests/instrument.rs @@ -252,3 +252,75 @@ fn impl_trait_return_type() { handle.assert_finished(); } + +#[test] +fn name_ident() { + const MY_NAME: &str = "my_name"; + #[instrument(name = MY_NAME)] + fn name() {} + + let span_name = expect::span().named(MY_NAME); + + let (subscriber, handle) = subscriber::mock() + .new_span(span_name.clone()) + .enter(span_name.clone()) + .exit(span_name.clone()) + .drop_span(span_name) + .only() + .run_with_handle(); + + with_default(subscriber, || { + name(); + }); + + handle.assert_finished(); +} + +#[test] +fn target_ident() { + const MY_TARGET: &str = "my_target"; + + #[instrument(target = MY_TARGET)] + fn target() {} + + let span_target = expect::span().named("target").with_target(MY_TARGET); + + let (subscriber, handle) = subscriber::mock() + .new_span(span_target.clone()) + .enter(span_target.clone()) + .exit(span_target.clone()) + .drop_span(span_target) + .only() + .run_with_handle(); + + with_default(subscriber, || { + target(); + }); + + handle.assert_finished(); +} + +#[test] +fn target_name_ident() { + const MY_NAME: &str = "my_name"; + const MY_TARGET: &str = "my_target"; + + #[instrument(target = MY_TARGET, name = MY_NAME)] + fn name_target() {} + + let span_name_target = expect::span().named(MY_NAME).with_target(MY_TARGET); + + let (subscriber, handle) = subscriber::mock() + .new_span(span_name_target.clone()) + .enter(span_name_target.clone()) + .exit(span_name_target.clone()) + .drop_span(span_name_target) + .only() + .run_with_handle(); + + with_default(subscriber, || { + name_target(); + }); + + handle.assert_finished(); +} From 59a48c778dea2cfc21709abb67d5fb8b6ee6973e Mon Sep 17 00:00:00 2001 From: Gabriel Goller Date: Sat, 25 May 2024 22:54:05 +0200 Subject: [PATCH 15/21] docs: remove non-existing method in comments (#2894) In the documentation of the layer context span_scope method, the note contained a reference to a `scope()` method, which was removed some time ago. Also fixed a phrasing error above. Fixes: #2890 --- tracing-subscriber/src/layer/context.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tracing-subscriber/src/layer/context.rs b/tracing-subscriber/src/layer/context.rs index 46254994f1..5ab6f84821 100644 --- a/tracing-subscriber/src/layer/context.rs +++ b/tracing-subscriber/src/layer/context.rs @@ -316,11 +316,10 @@ where /// Returns an iterator over the [stored data] for all the spans in the /// current context, starting with the specified span and ending with the - /// root of the trace tree and ending with the current span. + /// root of the trace tree. /// ///
-    /// Note: Compared to scope this
-    /// returns the spans in reverse order (from leaf to root). Use
+    /// Note: This returns the spans in reverse order (from leaf to root). Use
     /// Scope::from_root
     /// in case root-to-leaf ordering is desired.
     /// 
From f3d83a1c00c36509344f97c654c33b5b25d32850 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 16/21] 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 35b69967ec..3f9dce667e 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 5e9f65d075..e7cbf95461 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 55e9b81bc4..25b5bbe0c0 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 (subscriber, handle) = subscriber::mock() + .event(expect::event().with_fields(expect::field("crate").with_value(&"tracing"))) + .only() + .run_with_handle(); + + with_default(subscriber, || error!(crate = "tracing", "message")); + handle.assert_finished(); +} diff --git a/tracing/tests/span.rs b/tracing/tests/span.rs index bd5bed0d2f..9f4e5c45b8 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(); +} From 322c7e4e66604f5c2c14d339763fac73054d7b76 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 24 Jul 2024 10:53:17 -0700 Subject: [PATCH 17/21] fix: prefix macro calls with ::core to avoid clashing with local macros (#3024) fix: prefix macro calls with `__macro_support ` to avoid clashes with local macros Fixes: This ensures that the tracing lib correctly builds when a crate is named `core`. See https://github.com/tokio-rs/tracing/issues/2761 and https://github.com/tokio-rs/tracing/issues/2762 for more info. --- tracing-core/src/lib.rs | 14 +++++++++++--- tracing/src/lib.rs | 2 +- tracing/src/macros.rs | 12 ++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tracing-core/src/lib.rs b/tracing-core/src/lib.rs index bcb13533da..4286d88c33 100644 --- a/tracing-core/src/lib.rs +++ b/tracing-core/src/lib.rs @@ -147,6 +147,14 @@ #[cfg(not(feature = "std"))] extern crate alloc; +#[doc(hidden)] +pub mod __macro_support { + // Re-export the `core` functions that are used in macros. This allows + // a crate to be named `core` and avoid name clashes. + // See here: https://github.com/tokio-rs/tracing/issues/2761 + pub use core::{file, line, module_path, option::Option}; +} + /// Statically constructs an [`Identifier`] for the provided [`Callsite`]. /// /// This may be used in contexts such as static initializers. @@ -244,9 +252,9 @@ macro_rules! metadata { $name, $target, $level, - ::core::option::Option::Some(file!()), - ::core::option::Option::Some(line!()), - ::core::option::Option::Some(module_path!()), + $crate::__macro_support::Option::Some($crate::__macro_support::file!()), + $crate::__macro_support::Option::Some($crate::__macro_support::line!()), + $crate::__macro_support::Option::Some($crate::__macro_support::module_path!()), $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)), $kind, ) diff --git a/tracing/src/lib.rs b/tracing/src/lib.rs index 3425da591f..2c01d6d456 100644 --- a/tracing/src/lib.rs +++ b/tracing/src/lib.rs @@ -988,7 +988,7 @@ pub mod __macro_support { // Re-export the `core` functions that are used in macros. This allows // a crate to be named `core` and avoid name clashes. // See here: https://github.com/tokio-rs/tracing/issues/2761 - pub use core::{concat, format_args, iter::Iterator, option::Option}; + pub use core::{concat, file, format_args, iter::Iterator, line, option::Option}; /// Callsite implementation used by macro-generated code. /// diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs index e7cbf95461..156334a356 100644 --- a/tracing/src/macros.rs +++ b/tracing/src/macros.rs @@ -694,9 +694,9 @@ macro_rules! event { static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { name: $crate::__macro_support::concat!( "event ", - file!(), + $crate::__macro_support::file!(), ":", - line!() + $crate::__macro_support::line!() ), kind: $crate::metadata::Kind::EVENT, target: $target, @@ -855,9 +855,9 @@ macro_rules! event { static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { name: $crate::__macro_support::concat!( "event ", - file!(), + $crate::__macro_support::file!(), ":", - line!() + $crate::__macro_support::line!() ), kind: $crate::metadata::Kind::EVENT, target: $target, @@ -1188,9 +1188,9 @@ macro_rules! enabled { static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { name: $crate::__macro_support::concat!( "enabled ", - file!(), + $crate::__macro_support::file!(), ":", - line!() + $crate::__macro_support::line!() ), kind: $kind.hint(), target: $target, From c15bff6f768f8030dc8cc9ba39ccf4b4afda6d18 Mon Sep 17 00:00:00 2001 From: Hayden Stainsby Date: Mon, 29 Jul 2024 20:54:48 +0200 Subject: [PATCH 18/21] fix: correct SerializeField definition and doc formatting (#3040) Clippy in 1.80.0 alerted us to the fact that `SerializeField` was never constructed (and due to its non-`pub` member, it can't be constructed outside the `tracing-serde` crate where it's from). This change fixes the definition to hold a reference to a `Field`, which is what the other `Serialize*` types do. It also implements `AsSerde` for this type and uses it inside the `SerializeFieldSet` type. As a bonus, Clippy is now also happy that the type is constructed. The example collector in the `tracing-serde` crate was also renamed from `JsonSubscriber` to `JsonCollector`. Some additional doc formatting issues in `tracing-subscriber` were fixed so that list items that run to multiple lines are correctly indented. --- tracing-serde/src/lib.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tracing-serde/src/lib.rs b/tracing-serde/src/lib.rs index 801280e0ff..eb29e8180b 100644 --- a/tracing-serde/src/lib.rs +++ b/tracing-serde/src/lib.rs @@ -75,6 +75,12 @@ //! next_id: AtomicUsize, // you need to assign span IDs, so you need a counter //! } //! +//! impl JsonSubscriber { +//! fn new() -> Self { +//! Self { next_id: 1.into() } +//! } +//! } +//! //! impl Subscriber for JsonSubscriber { //! //! fn new_span(&self, attrs: &Attributes<'_>) -> Id { @@ -97,7 +103,7 @@ //! } //! //! // ... -//! # fn enabled(&self, _: &Metadata<'_>) -> bool { false } +//! # fn enabled(&self, _: &Metadata<'_>) -> bool { true } //! # fn enter(&self, _: &Id) {} //! # fn exit(&self, _: &Id) {} //! # fn record(&self, _: &Id, _: &Record<'_>) {} @@ -199,6 +205,18 @@ use tracing_core::{ pub mod fields; +#[derive(Debug)] +pub struct SerializeField<'a>(&'a Field); + +impl<'a> Serialize for SerializeField<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.0.name()) + } +} + #[derive(Debug)] pub struct SerializeFieldSet<'a>(&'a FieldSet); @@ -209,7 +227,7 @@ impl<'a> Serialize for SerializeFieldSet<'a> { { let mut seq = serializer.serialize_seq(Some(self.0.len()))?; for element in self.0 { - seq.serialize_element(element.name())?; + seq.serialize_element(&SerializeField(&element))?; } seq.end() } @@ -552,6 +570,14 @@ impl<'a> AsSerde<'a> for Level { } } +impl<'a> AsSerde<'a> for Field { + type Serializable = SerializeField<'a>; + + fn as_serde(&'a self) -> Self::Serializable { + SerializeField(self) + } +} + impl<'a> AsSerde<'a> for FieldSet { type Serializable = SerializeFieldSet<'a>; @@ -572,6 +598,8 @@ impl<'a> self::sealed::Sealed for Record<'a> {} impl<'a> self::sealed::Sealed for Metadata<'a> {} +impl self::sealed::Sealed for Field {} + impl self::sealed::Sealed for FieldSet {} mod sealed { From 9210501eeb59770bd7b6f7c03261b111bf73b85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ml=C3=A1dek?= Date: Wed, 30 Oct 2024 15:05:25 +0100 Subject: [PATCH 19/21] Add `json-subscriber` to ecosystem (#3121) ## Motivation I've created a library for better customization of JSON log lines and would like to make it more discoverable. This subscriber could help with a lot of issues such as #1531 ## Solution Add `json-subscriber` to the ecosystem. --- tracing/README.md | 2 ++ tracing/src/lib.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tracing/README.md b/tracing/README.md index b8758ef3ac..8585b6e86e 100644 --- a/tracing/README.md +++ b/tracing/README.md @@ -397,6 +397,7 @@ maintained by the `tokio` project. These include: - [`sentry-tracing`] provides a layer for reporting events and traces to [Sentry]. - [`tracing-loki`] provides a layer for shipping logs to [Grafana Loki]. - [`tracing-logfmt`] provides a layer that formats events and spans into the logfmt format. +- [`json-subscriber`] provides a layer for emitting JSON logs. The output can be customized much more than with [`FmtSubscriber`]'s JSON output. If you're the maintainer of a `tracing` ecosystem crate not listed above, please let us know! We'd love to add your project to the list! @@ -428,6 +429,7 @@ please let us know! We'd love to add your project to the list! [`tracing-loki`]: https://crates.io/crates/tracing-loki [Grafana Loki]: https://grafana.com/oss/loki/ [`tracing-logfmt`]: https://crates.io/crates/tracing-logfmt +[`json-subscriber`]: https://crates.io/crates/json-subscriber **Note:** that some of the ecosystem crates are currently unreleased and undergoing active development. They may be less stable than `tracing` and diff --git a/tracing/src/lib.rs b/tracing/src/lib.rs index 2c01d6d456..8b6c7f0b95 100644 --- a/tracing/src/lib.rs +++ b/tracing/src/lib.rs @@ -756,6 +756,7 @@ //! - [`reqwest-tracing`] provides a middleware to trace [`reqwest`] HTTP requests. //! - [`tracing-cloudwatch`] provides a layer that sends events to AWS CloudWatch Logs. //! - [`clippy-tracing`] provides a tool to add, remove and check for `tracing::instrument`. +//! - [`json-subscriber`] provides a subscriber for emitting JSON logs. The output can be customized much more than with [`tracing-subscriber`]'s JSON output. //! //! If you're the maintainer of a `tracing` ecosystem crate not listed above, //! please let us know! We'd love to add your project to the list! @@ -799,6 +800,7 @@ //! [`reqwest`]: https://crates.io/crates/reqwest //! [`tracing-cloudwatch`]: https://crates.io/crates/tracing-cloudwatch //! [`clippy-tracing`]: https://crates.io/crates/clippy-tracing +//! [`json-subscriber`]: https://crates.io/crates/json-subscriber //! //!
 //!     Note: Some of these ecosystem crates are currently

From b6cb99ecb65bdf8577a679b13c300d3353946aff Mon Sep 17 00:00:00 2001
From: Rustin 
Date: Tue, 19 Nov 2024 06:30:09 +0800
Subject: [PATCH 20/21] tracing: add index API for `Field` (#2820)

## Motivation

Expose the index of the field in order to support cases such as sending field information
by index instead of by the string name in Tokio Console. Details:
https://github.com/tokio-rs/console/issues/462#issuecomment-1830842319

## Solution

Adds a new API which exposes the index of a field, which is how it is stored internally
(together with a reference to the `FieldSet` containing the ordered field names.

Signed-off-by: hi-rustin 
Co-authored-by: Hayden Stainsby 
---
 tracing-core/src/field.rs | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/tracing-core/src/field.rs b/tracing-core/src/field.rs
index 52d1dcf8a4..c09b863591 100644
--- a/tracing-core/src/field.rs
+++ b/tracing-core/src/field.rs
@@ -804,6 +804,11 @@ impl Field {
     pub fn name(&self) -> &'static str {
         self.fields.names[self.i]
     }
+
+    /// Returns the index of this field in its [`FieldSet`].
+    pub fn index(&self) -> usize {
+        self.i
+    }
 }
 
 impl fmt::Display for Field {
@@ -1174,6 +1179,17 @@ mod test {
         assert!(valueset.is_empty());
     }
 
+    #[test]
+    fn index_of_field_in_fieldset_is_correct() {
+        let fields = TEST_META_1.fields();
+        let foo = fields.field("foo").unwrap();
+        assert_eq!(foo.index(), 0);
+        let bar = fields.field("bar").unwrap();
+        assert_eq!(bar.index(), 1);
+        let baz = fields.field("baz").unwrap();
+        assert_eq!(baz.index(), 2);
+    }
+
     #[test]
     fn empty_value_set_is_empty() {
         let fields = TEST_META_1.fields();

From 5294a844793c8049b4a8726b3096f1fa603a140f Mon Sep 17 00:00:00 2001
From: Eliza Weisman 
Date: Fri, 26 Feb 2021 14:35:03 -0800
Subject: [PATCH 21/21] subscriber: set `log` max level when reloading (#1270)

This modifies the `tracing_subscriber::reload` layer to also set the
`log` crate's max level with the current max `tracing` level filter
after reloading. If reloading the subscriber caused the max `tracing`
level to change, this ensures that the change is propagated to the `log`
crate as well. In the case where the max level was made more verbose,
this will ensure that `log` records which were previously disabled are
enabled correctly; in the case where it was made less verbose, this
improve performance by not having to perfrom more costly filtering for
those `log` records.

The `log` max level is set only after rebuilding the callsite interest
cache, which is what sets the max `tracing` level filter. This ensures
that we pass the latest state to the `log` crate.

Signed-off-by: Eliza Weisman 
---
 tracing-subscriber/src/reload.rs              | 10 +++++
 .../tests/reload_max_log_level.rs             | 37 +++++++++++++++++++
 2 files changed, 47 insertions(+)
 create mode 100644 tracing-subscriber/tests/reload_max_log_level.rs

diff --git a/tracing-subscriber/src/reload.rs b/tracing-subscriber/src/reload.rs
index 096f83d38a..d926c78f5f 100644
--- a/tracing-subscriber/src/reload.rs
+++ b/tracing-subscriber/src/reload.rs
@@ -317,6 +317,16 @@ impl Handle {
         drop(lock);
 
         callsite::rebuild_interest_cache();
+
+        // If the `log` crate compatibility feature is in use, set `log`'s max
+        // level as well, in case the max `tracing` level changed. We do this
+        // *after* rebuilding the interest cache, as that's when the `tracing`
+        // max level filter is re-computed.
+        #[cfg(feature = "tracing-log")]
+        tracing_log::log::set_max_level(tracing_log::AsLog::as_log(
+            &crate::filter::LevelFilter::current(),
+        ));
+
         Ok(())
     }
 
diff --git a/tracing-subscriber/tests/reload_max_log_level.rs b/tracing-subscriber/tests/reload_max_log_level.rs
new file mode 100644
index 0000000000..69230f0013
--- /dev/null
+++ b/tracing-subscriber/tests/reload_max_log_level.rs
@@ -0,0 +1,37 @@
+#![cfg(all(feature = "env-filter", feature = "tracing-log"))]
+
+use tracing::{self, Level};
+use tracing_mock::{expect, subscriber};
+use tracing_subscriber::{filter::LevelFilter, prelude::*, reload};
+
+#[test]
+fn reload_max_log_level() {
+    let (subscriber, finished) = subscriber::mock()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
+        .run_with_handle();
+    let (filter, reload_handle) = reload::Layer::new(LevelFilter::INFO);
+    subscriber.with(filter).init();
+
+    assert!(log::log_enabled!(log::Level::Info));
+    assert!(!log::log_enabled!(log::Level::Debug));
+    assert!(!log::log_enabled!(log::Level::Trace));
+
+    log::debug!("i'm disabled");
+    log::info!("i'm enabled");
+
+    reload_handle
+        .reload(Level::DEBUG)
+        .expect("reloading succeeds");
+
+    assert!(log::log_enabled!(log::Level::Info));
+    assert!(log::log_enabled!(log::Level::Debug));
+    assert!(!log::log_enabled!(log::Level::Trace));
+
+    log::debug!("i'm enabled now");
+    log::info!("i'm still enabled, too");
+
+    finished.assert_finished();
+}