diff --git a/README.md b/README.md index cfe1be8a19..58a841b109 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,7 @@ are not maintained by the `tokio` project. These include: - [`tracing-actix-web`] provides `tracing` integration for the `actix-web` web framework. - [`tracing-actix`] provides `tracing` integration for the `actix` actor framework. +- [`axum-insights`] provides `tracing` integration and Application insights export for the `axum` web framework. - [`tracing-gelf`] implements a subscriber for exporting traces in Greylog GELF format. - [`tracing-coz`] provides integration with the [coz] causal profiler @@ -401,6 +402,8 @@ are not maintained by the `tokio` project. These include: - [`tracing-logfmt`] provides a layer that formats events and spans into the logfmt format. - [`tracing-chrome`] provides a layer that exports trace data that can be viewed in `chrome://tracing`. - [`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`. (if you're the maintainer of a `tracing` ecosystem crate not in this list, please let us know!) @@ -411,6 +414,7 @@ please let us know!) [honeycomb.io]: https://www.honeycomb.io/ [`tracing-actix`]: https://crates.io/crates/tracing-actix [`tracing-actix-web`]: https://crates.io/crates/tracing-actix-web +[`axum-insights`]: https://crates.io/crates/axum-insights [`tracing-gelf`]: https://crates.io/crates/tracing-gelf [`tracing-coz`]: https://crates.io/crates/tracing-coz [coz]: https://github.com/plasma-umass/coz @@ -443,6 +447,8 @@ please let us know!) [`tracing-chrome`]: https://crates.io/crates/tracing-chrome [`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing [`reqwest`]: https://crates.io/crates/reqwest +[`tracing-cloudwatch`]: https://crates.io/crates/tracing-cloudwatch +[`clippy-tracing`]: https://crates.io/crates/clippy-tracing **Note:** that some of the ecosystem crates are currently unreleased and undergoing active development. They may be less stable than `tracing` and @@ -458,14 +464,17 @@ Tracing. * [Diagnostics with Tracing][tokio-blog-2019-08] on the Tokio blog, August 2019 * [Production-Grade Logging in Rust Applications][production-logging-2020], November 2020 * [Custom Logging in Rust using `tracing` and `tracing-subscriber`, part 1][custom-logging-part-1] and [part 2][custom-logging-part-2], October 2021 +* [Instrumenting Axum projects][detsys-blog-2023-08], August 2023 [tokio-blog-2019-08]: https://tokio.rs/blog/2019-08-tracing/ +[detsys-blog-2023-08]: https://determinate.systems/posts/instrumenting-axum #### Talks * [Bay Area Rust Meetup talk and Q&A][bay-rust-2019-03], March 2019 * [RustConf 2019 talk][rust-conf-2019-08-video] and [slides][rust-conf-2019-08-slides], August 2019 * [Are we observable yet? @ RustyDays talk][rusty-days-2020-08-video] and [slides][rusty-days-2020-08-slides], August 2020 +* [Crabs with instruments!][tremorcon-2021-09], September 2021 [bay-rust-2019-03]: https://www.youtube.com/watch?v=j_kXRg3zlec [rust-conf-2019-08-video]: https://www.youtube.com/watch?v=JjItsfqFIdo @@ -475,6 +484,7 @@ Tracing. [production-logging-2020]: https://medium.com/better-programming/production-grade-logging-in-rust-applications-2c7fffd108a6 [custom-logging-part-1]: https://burgers.io/custom-logging-in-rust-using-tracing [custom-logging-part-2]: https://burgers.io/custom-logging-in-rust-using-tracing-part-2 +[tremorcon-2021-09]: https://www.youtube.com/watch?v=ZC7fyqshun8 Help us expand this list! If you've written or spoken about Tracing, or know of resources that aren't listed, please open a pull request adding them. diff --git a/examples/examples/fmt-compact.rs b/examples/examples/fmt-compact.rs index a4899ce379..14cdd8a45f 100644 --- a/examples/examples/fmt-compact.rs +++ b/examples/examples/fmt-compact.rs @@ -7,7 +7,7 @@ fn main() { .compact() // enable everything .with_max_level(tracing::Level::TRACE) - // sets this to be the default, global collector for this application. + // sets this to be the default, global subscriber for this application. .init(); let number_of_yaks = 3; diff --git a/examples/examples/fmt-source-locations.rs b/examples/examples/fmt-source-locations.rs index 799ebb17d5..b4b05b3027 100644 --- a/examples/examples/fmt-source-locations.rs +++ b/examples/examples/fmt-source-locations.rs @@ -14,7 +14,7 @@ fn main() { .with_line_number(true) // disable targets .with_target(false) - // sets this to be the default, global collector for this application. + // sets this to be the default, global subscriber for this application. .init(); let number_of_yaks = 3; diff --git a/examples/examples/panic_hook.rs b/examples/examples/panic_hook.rs index 20addd20b9..cb5f50bd1c 100644 --- a/examples/examples/panic_hook.rs +++ b/examples/examples/panic_hook.rs @@ -30,7 +30,7 @@ fn main() { // On nightly Rust, where the `PanicInfo` type also exposes a // `message()` method returning just the message, we could record // just the message instead of the entire `fmt::Display` - // implementation, avoiding the duplciated location + // implementation, avoiding the duplicated location tracing::error!( message = %panic, panic.file = location.file(), diff --git a/netlify.toml b/netlify.toml index 6e3beff1a6..2437d8c3b9 100644 --- a/netlify.toml +++ b/netlify.toml @@ -8,6 +8,7 @@ [build.environment] RUSTDOCFLAGS=""" -D warnings \ + --force-warn rustdoc::redundant-explicit-links \ --force-warn renamed-and-removed-lints \ --cfg docsrs \ --cfg tracing_unstable diff --git a/tracing-appender/src/lib.rs b/tracing-appender/src/lib.rs index 25279fb0ec..9fe789e50a 100644 --- a/tracing-appender/src/lib.rs +++ b/tracing-appender/src/lib.rs @@ -26,20 +26,34 @@ //! - Using a combination of [`NonBlocking`][non_blocking] and [`RollingFileAppender`][rolling_struct] to allow writes to a log file //! without blocking. //! -//! ## Rolling File Appender +//! ## File Appender +//! +//! The [`rolling` module][rolling] provides functions to create rolling and non-rolling file +//! appenders. +//! +//! Rolling file appender rotation options are [`Rotation::MINUTELY`](rolling::Rotation::MINUTELY), +//! [`Rotation::HOURLY`](rolling::Rotation::HOURLY), and +//! [`Rotation::DAILY`](rolling::Rotation::DAILY). +//! +//! To create a non-rolling file appender, use +//! [`tracing_appender::rolling::never(/*...*/)`](rolling::never) or +//! [`Rotation::NEVER`](rolling::Rotation::NEVER). +//! +//! The following example creates an hourly rotating file appender that writes to +//! `/some/directory/prefix.log.YYYY-MM-DD-HH`: //! //! ```rust //! # fn docs() { //! let file_appender = tracing_appender::rolling::hourly("/some/directory", "prefix.log"); //! # } //! ``` -//! This creates an hourly rotating file appender that writes to `/some/directory/prefix.log.YYYY-MM-DD-HH`. -//! [`Rotation::DAILY`](rolling::Rotation::DAILY) and [`Rotation::NEVER`](rolling::Rotation::NEVER) are the other available options. //! -//! The file appender implements [`std::io::Write`][write]. To be used with [`tracing_subscriber::FmtSubscriber`][fmt_subscriber], -//! it must be combined with a [`MakeWriter`][make_writer] implementation to be able to record tracing spans/event. +//! The file appender implements [`std::io::Write`][write]. To be used with +//! [`tracing_subscriber::FmtSubscriber`][fmt_subscriber], it must be combined with a +//! [`MakeWriter`][make_writer] implementation to be able to record tracing spans/event. //! -//! The [`rolling` module][rolling]'s documentation provides more detail on how to use this file appender. +//! See the [`rolling` module][rolling]'s documentation for more detail on how to use this file +//! appender. //! //! ## Non-Blocking Writer //! diff --git a/tracing-appender/src/rolling.rs b/tracing-appender/src/rolling.rs index 15ae35ba06..cce6139871 100644 --- a/tracing-appender/src/rolling.rs +++ b/tracing-appender/src/rolling.rs @@ -264,7 +264,7 @@ impl fmt::Debug for RollingFileAppender { } } -/// Creates a minutely, rolling file appender. This will rotate the log file once per minute. +/// Creates a minutely-rotating file appender. This will rotate the log file once per minute. /// /// The appender returned by `rolling::minutely` can be used with `non_blocking` to create /// a non-blocking, minutely file appender. @@ -299,7 +299,7 @@ pub fn minutely( RollingFileAppender::new(Rotation::MINUTELY, directory, file_name_prefix) } -/// Creates an hourly, rolling file appender. +/// Creates an hourly-rotating file appender. /// /// The appender returned by `rolling::hourly` can be used with `non_blocking` to create /// a non-blocking, hourly file appender. @@ -334,7 +334,7 @@ pub fn hourly( RollingFileAppender::new(Rotation::HOURLY, directory, file_name_prefix) } -/// Creates a file appender that rotates daily. +/// Creates a daily-rotating file appender. /// /// The appender returned by `rolling::daily` can be used with `non_blocking` to create /// a non-blocking, daily file appender. @@ -370,13 +370,13 @@ pub fn daily( RollingFileAppender::new(Rotation::DAILY, directory, file_name_prefix) } -/// Creates a non-rolling, file appender +/// Creates a non-rolling file appender. /// /// The appender returned by `rolling::never` can be used with `non_blocking` to create /// a non-blocking, non-rotating appender. /// /// The location of the log file will be specified the `directory` passed in. -/// `file_name` specifies the prefix of the log file. No date or time is appended. +/// `file_name` specifies the complete name of the log file (no date or time is appended). /// /// # Examples /// diff --git a/tracing-attributes/Cargo.toml b/tracing-attributes/Cargo.toml index 67e546f43a..9c126ad81b 100644 --- a/tracing-attributes/Cargo.toml +++ b/tracing-attributes/Cargo.toml @@ -39,7 +39,7 @@ proc-macro = true async-await = [] [dependencies] -proc-macro2 = "1.0.40" +proc-macro2 = "1.0.60" syn = { version = "2.0", default-features = false, features = ["full", "parsing", "printing", "visit-mut", "clone-impls", "extra-traits", "proc-macro"] } quote = "1.0.20" diff --git a/tracing-attributes/src/expand.rs b/tracing-attributes/src/expand.rs index eb7be8f47e..a7123e5239 100644 --- a/tracing-attributes/src/expand.rs +++ b/tracing-attributes/src/expand.rs @@ -66,11 +66,11 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>( let fake_return_edge = quote_spanned! {return_span=> #[allow( unknown_lints, unreachable_code, clippy::diverging_sub_expression, - clippy::let_unit_value, clippy::unreachable, clippy::let_with_type_underscore + clippy::let_unit_value, clippy::unreachable, clippy::let_with_type_underscore, + clippy::empty_loop )] if false { - let __tracing_attr_fake_return: #return_type = - unreachable!("this is just for type inference, and is unreachable code"); + let __tracing_attr_fake_return: #return_type = loop {}; return __tracing_attr_fake_return; } }; @@ -343,7 +343,7 @@ fn gen_block( // regression in case the level is enabled. let __tracing_attr_span; let __tracing_attr_guard; - if tracing::level_enabled!(#level) { + if tracing::level_enabled!(#level) || tracing::if_log_enabled!(#level, {true} else {false}) { __tracing_attr_span = #span; #follows_from __tracing_attr_guard = __tracing_attr_span.enter(); diff --git a/tracing-attributes/tests/async_fn.rs b/tracing-attributes/tests/async_fn.rs index d6d874ffd7..ed36d0d6fb 100644 --- a/tracing-attributes/tests/async_fn.rs +++ b/tracing-attributes/tests/async_fn.rs @@ -84,16 +84,16 @@ fn repro_1831_2() -> impl Future> { #[test] fn async_fn_only_enters_for_polls() { let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("test_async_fn")) - .enter(span::mock().named("test_async_fn")) - .event(event::mock().with_fields(field::mock("awaiting").with_value(&true))) - .exit(span::mock().named("test_async_fn")) - .enter(span::mock().named("test_async_fn")) - .exit(span::mock().named("test_async_fn")) - .enter(span::mock().named("test_async_fn")) - .exit(span::mock().named("test_async_fn")) - .drop_span(span::mock().named("test_async_fn")) - .done() + .new_span(expect::span().named("test_async_fn")) + .enter(expect::span().named("test_async_fn")) + .event(expect::event().with_fields(expect::field("awaiting").with_value(&true))) + .exit(expect::span().named("test_async_fn")) + .enter(expect::span().named("test_async_fn")) + .exit(expect::span().named("test_async_fn")) + .enter(expect::span().named("test_async_fn")) + .exit(expect::span().named("test_async_fn")) + .drop_span(expect::span().named("test_async_fn")) + .only() .run_with_handle(); with_default(subscriber, || { block_on_future(async { test_async_fn(2).await }).unwrap(); @@ -113,14 +113,14 @@ fn async_fn_nested() { tracing::trace!(nested = true); } - let span = span::mock().named("test_async_fns_nested"); - let span2 = span::mock().named("test_async_fns_nested_other"); + let span = expect::span().named("test_async_fns_nested"); + let span2 = expect::span().named("test_async_fns_nested_other"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .new_span(span2.clone()) .enter(span2.clone()) - .event(event::mock().with_fields(field::mock("nested").with_value(&true))) + .event(expect::event().with_fields(expect::field("nested").with_value(&true))) .exit(span2.clone()) .enter(span2.clone()) .exit(span2.clone()) @@ -129,7 +129,7 @@ fn async_fn_nested() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -191,26 +191,26 @@ fn async_fn_with_async_trait() { } } - let span = span::mock().named("foo"); - let span2 = span::mock().named("bar"); - let span3 = span::mock().named("baz"); + let span = expect::span().named("foo"); + let span2 = expect::span().named("bar"); + let span3 = expect::span().named("baz"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone() - .with_field(field::mock("self")) - .with_field(field::mock("v")), + .with_field(expect::field("self")) + .with_field(expect::field("v")), ) .enter(span.clone()) .new_span(span3.clone()) .enter(span3.clone()) - .event(event::mock().with_fields(field::mock("val").with_value(&2u64))) + .event(expect::event().with_fields(expect::field("val").with_value(&2u64))) .exit(span3.clone()) .enter(span3.clone()) .exit(span3.clone()) .drop_span(span3) - .new_span(span2.clone().with_field(field::mock("self"))) + .new_span(span2.clone().with_field(expect::field("self"))) .enter(span2.clone()) - .event(event::mock().with_fields(field::mock("val").with_value(&5u64))) + .event(expect::event().with_fields(expect::field("val").with_value(&5u64))) .exit(span2.clone()) .enter(span2.clone()) .exit(span2.clone()) @@ -219,7 +219,7 @@ fn async_fn_with_async_trait() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -255,15 +255,15 @@ fn async_fn_with_async_trait_and_fields_expressions() { async fn call(&mut self, _v: usize) {} } - let span = span::mock().named("call"); + let span = expect::span().named("call"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("_v") + expect::field("_v") .with_value(&5usize) - .and(field::mock("test").with_value(&tracing::field::debug(10))) - .and(field::mock("val").with_value(&42u64)) - .and(field::mock("val2").with_value(&42u64)), + .and(expect::field("test").with_value(&tracing::field::debug(10))) + .and(expect::field("val").with_value(&42u64)) + .and(expect::field("val2").with_value(&42u64)), ), ) .enter(span.clone()) @@ -271,7 +271,7 @@ fn async_fn_with_async_trait_and_fields_expressions() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -323,26 +323,26 @@ fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() { } //let span = span::mock().named("call"); - let span2 = span::mock().named("call_with_self"); - let span3 = span::mock().named("call_with_mut_self"); - let span4 = span::mock().named("sync_fun"); + let span2 = expect::span().named("call_with_self"); + let span3 = expect::span().named("call_with_mut_self"); + let span4 = expect::span().named("sync_fun"); let (subscriber, handle) = subscriber::mock() /*.new_span(span.clone() .with_field( - field::mock("Self").with_value(&"TestImpler"))) + expect::field("Self").with_value(&"TestImpler"))) .enter(span.clone()) .exit(span.clone()) .drop_span(span)*/ .new_span( span2 .clone() - .with_field(field::mock("Self").with_value(&std::any::type_name::())), + .with_field(expect::field("Self").with_value(&std::any::type_name::())), ) .enter(span2.clone()) .new_span( span4 .clone() - .with_field(field::mock("Self").with_value(&std::any::type_name::())), + .with_field(expect::field("Self").with_value(&std::any::type_name::())), ) .enter(span4.clone()) .exit(span4.clone()) @@ -355,14 +355,14 @@ fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() { .new_span( span3 .clone() - .with_field(field::mock("Self").with_value(&std::any::type_name::())), + .with_field(expect::field("Self").with_value(&std::any::type_name::())), ) .enter(span3.clone()) .exit(span3.clone()) .enter(span3.clone()) .exit(span3.clone()) .drop_span(span3) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -397,7 +397,7 @@ fn out_of_scope_fields() { } } - let span = span::mock().named("call"); + let span = expect::span().named("call"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) @@ -405,7 +405,7 @@ fn out_of_scope_fields() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -430,8 +430,8 @@ fn manual_impl_future() { } } - let span = span::mock().named("manual_impl_future"); - let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true)); + let span = expect::span().named("manual_impl_future"); + let poll_event = || expect::event().with_fields(expect::field("poll").with_value(&true)); let (subscriber, handle) = subscriber::mock() // await manual_impl_future @@ -442,7 +442,7 @@ fn manual_impl_future() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -463,8 +463,8 @@ fn manual_box_pin() { }) } - let span = span::mock().named("manual_box_pin"); - let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true)); + let span = expect::span().named("manual_box_pin"); + let poll_event = || expect::event().with_fields(expect::field("poll").with_value(&true)); let (subscriber, handle) = subscriber::mock() // await manual_box_pin @@ -475,7 +475,7 @@ fn manual_box_pin() { .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/destructuring.rs b/tracing-attributes/tests/destructuring.rs index 09cf1ad534..cc4fecf3f2 100644 --- a/tracing-attributes/tests/destructuring.rs +++ b/tracing-attributes/tests/destructuring.rs @@ -7,21 +7,21 @@ fn destructure_tuples() { #[instrument] fn my_fn((arg1, arg2): (usize, usize)) {} - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("1")) - .and(field::mock("arg2").with_value(&format_args!("2"))) + .and(expect::field("arg2").with_value(&format_args!("2"))) .only(), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -36,23 +36,23 @@ fn destructure_nested_tuples() { #[instrument] fn my_fn(((arg1, arg2), (arg3, arg4)): ((usize, usize), (usize, usize))) {} - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("1")) - .and(field::mock("arg2").with_value(&format_args!("2"))) - .and(field::mock("arg3").with_value(&format_args!("3"))) - .and(field::mock("arg4").with_value(&format_args!("4"))) + .and(expect::field("arg2").with_value(&format_args!("2"))) + .and(expect::field("arg3").with_value(&format_args!("3"))) + .and(expect::field("arg4").with_value(&format_args!("4"))) .only(), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -67,17 +67,17 @@ fn destructure_refs() { #[instrument] fn my_fn(&arg1: &usize) {} - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone() - .with_field(field::mock("arg1").with_value(&1usize).only()), + .with_field(expect::field("arg1").with_value(&1usize).only()), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -94,21 +94,21 @@ fn destructure_tuple_structs() { #[instrument] fn my_fn(Foo(arg1, arg2): Foo) {} - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("1")) - .and(field::mock("arg2").with_value(&format_args!("2"))) + .and(expect::field("arg2").with_value(&format_args!("2"))) .only(), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -135,21 +135,21 @@ fn destructure_structs() { let _ = (arg1, arg2); } - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("1")) - .and(field::mock("arg2").with_value(&format_args!("2"))) + .and(expect::field("arg2").with_value(&format_args!("2"))) .only(), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -180,23 +180,23 @@ fn destructure_everything() { let _ = (arg1, arg2, arg3, arg4); } - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("1")) - .and(field::mock("arg2").with_value(&format_args!("2"))) - .and(field::mock("arg3").with_value(&format_args!("3"))) - .and(field::mock("arg4").with_value(&format_args!("4"))) + .and(expect::field("arg2").with_value(&format_args!("2"))) + .and(expect::field("arg3").with_value(&format_args!("3"))) + .and(expect::field("arg4").with_value(&format_args!("4"))) .only(), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/err.rs b/tracing-attributes/tests/err.rs index 485dd11961..bee7aa5f4e 100644 --- a/tracing-attributes/tests/err.rs +++ b/tracing-attributes/tests/err.rs @@ -21,19 +21,40 @@ fn err_suspicious_else() -> Result { #[test] fn test() { - let span = span::mock().named("err"); + let span = expect::span().named("err"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::ERROR)) + .event(expect::event().at_level(Level::ERROR)) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err().ok()); handle.assert_finished(); } +#[instrument(err)] +fn err_early_return() -> Result { + u8::try_from(1234)?; + Ok(5) +} + +#[test] +fn test_early_return() { + let span = expect::span().named("err_early_return"); + let (subscriber, handle) = subscriber::mock() + .new_span(span.clone()) + .enter(span.clone()) + .event(expect::event().at_level(Level::ERROR)) + .exit(span.clone()) + .drop_span(span) + .only() + .run_with_handle(); + with_default(subscriber, || err_early_return().ok()); + handle.assert_finished(); +} + #[instrument(err)] async fn err_async(polls: usize) -> Result { let future = PollN::new_ok(polls); @@ -44,23 +65,23 @@ async fn err_async(polls: usize) -> Result { #[test] fn test_async() { - let span = span::mock().named("err_async"); + let span = expect::span().named("err_async"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("awaiting").with_value(&true)) + expect::event() + .with_fields(expect::field("awaiting").with_value(&true)) .at_level(Level::TRACE), ) .exit(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::ERROR)) + .event(expect::event().at_level(Level::ERROR)) .exit(span.clone()) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { block_on_future(async { err_async(2).await }).ok(); @@ -76,14 +97,14 @@ fn err_mut(out: &mut u8) -> Result<(), TryFromIntError> { #[test] fn test_mut() { - let span = span::mock().named("err_mut"); + let span = expect::span().named("err_mut"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::ERROR)) + .event(expect::event().at_level(Level::ERROR)) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err_mut(&mut 0).ok()); handle.assert_finished(); @@ -100,23 +121,23 @@ async fn err_mut_async(polls: usize, out: &mut u8) -> Result<(), TryFromIntError #[test] fn test_mut_async() { - let span = span::mock().named("err_mut_async"); + let span = expect::span().named("err_mut_async"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("awaiting").with_value(&true)) + expect::event() + .with_fields(expect::field("awaiting").with_value(&true)) .at_level(Level::TRACE), ) .exit(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::ERROR)) + .event(expect::event().at_level(Level::ERROR)) .exit(span.clone()) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { block_on_future(async { err_mut_async(2, &mut 0).await }).ok(); @@ -133,17 +154,17 @@ fn impl_trait_return_type() { Ok(0..x) } - let span = span::mock().named("returns_impl_trait"); + let span = expect::span().named("returns_impl_trait"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone() - .with_field(field::mock("x").with_value(&10usize).only()), + .with_field(expect::field("x").with_value(&10usize).only()), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -162,13 +183,13 @@ fn err_dbg() -> Result { #[test] fn test_err_dbg() { - let span = span::mock().named("err_dbg"); + let span = expect::span().named("err_dbg"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock().at_level(Level::ERROR).with_fields( - field::mock("error") + expect::event().at_level(Level::ERROR).with_fields( + expect::field("error") // use the actual error value that will be emitted, so // that this test doesn't break if the standard library // changes the `fmt::Debug` output from the error type @@ -178,7 +199,7 @@ fn test_err_dbg() { ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err_dbg().ok()); handle.assert_finished(); @@ -186,20 +207,20 @@ fn test_err_dbg() { #[test] fn test_err_display_default() { - let span = span::mock().named("err"); + let span = expect::span().named("err"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock().at_level(Level::ERROR).with_fields( - field::mock("error") + expect::event().at_level(Level::ERROR).with_fields( + expect::field("error") // by default, errors will be emitted with their display values .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err())), ), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err().ok()); handle.assert_finished(); @@ -208,19 +229,19 @@ fn test_err_display_default() { #[test] fn test_err_custom_target() { let filter: EnvFilter = "my_target=error".parse().expect("filter should parse"); - let span = span::mock().named("error_span").with_target("my_target"); + let span = expect::span().named("error_span").with_target("my_target"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() + expect::event() .at_level(Level::ERROR) .with_target("my_target"), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); let subscriber = subscriber.with(filter); @@ -243,14 +264,14 @@ fn err_info() -> Result { #[test] fn test_err_info() { - let span = span::mock().named("err_info"); + let span = expect::span().named("err_info"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::INFO)) + .event(expect::event().at_level(Level::INFO)) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err_info().ok()); handle.assert_finished(); @@ -263,13 +284,13 @@ fn err_dbg_info() -> Result { #[test] fn test_err_dbg_info() { - let span = span::mock().named("err_dbg_info"); + let span = expect::span().named("err_dbg_info"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock().at_level(Level::INFO).with_fields( - field::mock("error") + expect::event().at_level(Level::INFO).with_fields( + expect::field("error") // use the actual error value that will be emitted, so // that this test doesn't break if the standard library // changes the `fmt::Debug` output from the error type @@ -279,7 +300,7 @@ fn test_err_dbg_info() { ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err_dbg_info().ok()); handle.assert_finished(); @@ -292,14 +313,14 @@ fn err_warn_info() -> Result { #[test] fn test_err_warn_info() { - let span = span::mock().named("err_warn_info").at_level(Level::WARN); + let span = expect::span().named("err_warn_info").at_level(Level::WARN); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) - .event(event::mock().at_level(Level::INFO)) + .event(expect::event().at_level(Level::INFO)) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || err_warn_info().ok()); handle.assert_finished(); diff --git a/tracing-attributes/tests/fields.rs b/tracing-attributes/tests/fields.rs index c178fbb3d3..a3b23d7ac2 100644 --- a/tracing-attributes/tests/fields.rs +++ b/tracing-attributes/tests/fields.rs @@ -1,8 +1,6 @@ use tracing::subscriber::with_default; use tracing_attributes::instrument; -use tracing_mock::field::mock; -use tracing_mock::span::NewSpan; -use tracing_mock::*; +use tracing_mock::{expect, span::NewSpan, subscriber}; #[instrument(fields(foo = "bar", dsa = true, num = 1))] fn fn_no_param() {} @@ -48,11 +46,11 @@ impl HasField { #[test] fn fields() { - let span = span::mock().with_field( - mock("foo") + let span = expect::span().with_field( + expect::field("foo") .with_value(&"bar") - .and(mock("dsa").with_value(&true)) - .and(mock("num").with_value(&1)) + .and(expect::field("dsa").with_value(&true)) + .and(expect::field("num").with_value(&1)) .only(), ); run_test(span, || { @@ -62,10 +60,10 @@ fn fields() { #[test] fn expr_field() { - let span = span::mock().with_field( - mock("s") + let span = expect::span().with_field( + expect::field("s") .with_value(&"hello world") - .and(mock("len").with_value(&"hello world".len())) + .and(expect::field("len").with_value(&"hello world".len())) .only(), ); run_test(span, || { @@ -75,11 +73,11 @@ fn expr_field() { #[test] fn two_expr_fields() { - let span = span::mock().with_field( - mock("s") + let span = expect::span().with_field( + expect::field("s") .with_value(&"hello world") - .and(mock("s.len").with_value(&"hello world".len())) - .and(mock("s.is_empty").with_value(&false)) + .and(expect::field("s.len").with_value(&"hello world".len())) + .and(expect::field("s.is_empty").with_value(&false)) .only(), ); run_test(span, || { @@ -89,19 +87,19 @@ fn two_expr_fields() { #[test] fn clashy_expr_field() { - let span = span::mock().with_field( + let span = expect::span().with_field( // Overriding the `s` field should record `s` as a `Display` value, // rather than as a `Debug` value. - mock("s") + expect::field("s") .with_value(&tracing::field::display("hello world")) - .and(mock("s.len").with_value(&"hello world".len())) + .and(expect::field("s.len").with_value(&"hello world".len())) .only(), ); run_test(span, || { fn_clashy_expr_field("hello world"); }); - let span = span::mock().with_field(mock("s").with_value(&"s").only()); + let span = expect::span().with_field(expect::field("s").with_value(&"s").only()); run_test(span, || { fn_clashy_expr_field2("hello world"); }); @@ -109,7 +107,8 @@ fn clashy_expr_field() { #[test] fn self_expr_field() { - let span = span::mock().with_field(mock("my_field").with_value(&"hello world").only()); + let span = + expect::span().with_field(expect::field("my_field").with_value(&"hello world").only()); run_test(span, || { let has_field = HasField { my_field: "hello world", @@ -120,10 +119,10 @@ fn self_expr_field() { #[test] fn parameters_with_fields() { - let span = span::mock().with_field( - mock("foo") + let span = expect::span().with_field( + expect::field("foo") .with_value(&"bar") - .and(mock("param").with_value(&1u32)) + .and(expect::field("param").with_value(&1u32)) .only(), ); run_test(span, || { @@ -133,7 +132,7 @@ fn parameters_with_fields() { #[test] fn empty_field() { - let span = span::mock().with_field(mock("foo").with_value(&"bar").only()); + let span = expect::span().with_field(expect::field("foo").with_value(&"bar").only()); run_test(span, || { fn_empty_field(); }); @@ -141,7 +140,7 @@ fn empty_field() { #[test] fn string_field() { - let span = span::mock().with_field(mock("s").with_value(&"hello world").only()); + let span = expect::span().with_field(expect::field("s").with_value(&"hello world").only()); run_test(span, || { fn_string(String::from("hello world")); }); @@ -150,9 +149,9 @@ fn string_field() { fn run_test T, T>(span: NewSpan, fun: F) { let (subscriber, handle) = subscriber::mock() .new_span(span) - .enter(span::mock()) - .exit(span::mock()) - .done() + .enter(expect::span()) + .exit(expect::span()) + .only() .run_with_handle(); with_default(subscriber, fun); diff --git a/tracing-attributes/tests/follows_from.rs b/tracing-attributes/tests/follows_from.rs index a589409ded..6b5526b82e 100644 --- a/tracing-attributes/tests/follows_from.rs +++ b/tracing-attributes/tests/follows_from.rs @@ -13,10 +13,10 @@ fn follows_from_current() {} #[test] fn follows_from_sync_test() { - let cause_a = span::mock().named("cause_a"); - let cause_b = span::mock().named("cause_b"); - let cause_c = span::mock().named("cause_c"); - let consequence = span::mock().named("with_follows_from_sync"); + let cause_a = expect::span().named("cause_a"); + let cause_b = expect::span().named("cause_b"); + let cause_c = expect::span().named("cause_c"); + let consequence = expect::span().named("with_follows_from_sync"); let (subscriber, handle) = subscriber::mock() .new_span(cause_a.clone()) @@ -28,7 +28,7 @@ fn follows_from_sync_test() { .follows_from(consequence.clone(), cause_c) .enter(consequence.clone()) .exit(consequence) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -44,10 +44,10 @@ fn follows_from_sync_test() { #[test] fn follows_from_async_test() { - let cause_a = span::mock().named("cause_a"); - let cause_b = span::mock().named("cause_b"); - let cause_c = span::mock().named("cause_c"); - let consequence = span::mock().named("with_follows_from_async"); + let cause_a = expect::span().named("cause_a"); + let cause_b = expect::span().named("cause_b"); + let cause_c = expect::span().named("cause_c"); + let consequence = expect::span().named("with_follows_from_async"); let (subscriber, handle) = subscriber::mock() .new_span(cause_a.clone()) @@ -61,7 +61,7 @@ fn follows_from_async_test() { .exit(consequence.clone()) .enter(consequence.clone()) .exit(consequence) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -79,8 +79,8 @@ fn follows_from_async_test() { #[test] fn follows_from_current_test() { - let cause = span::mock().named("cause"); - let consequence = span::mock().named("follows_from_current"); + let cause = expect::span().named("cause"); + let consequence = expect::span().named("follows_from_current"); let (subscriber, handle) = subscriber::mock() .new_span(cause.clone()) @@ -90,7 +90,7 @@ fn follows_from_current_test() { .enter(consequence.clone()) .exit(consequence) .exit(cause) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/instrument.rs b/tracing-attributes/tests/instrument.rs index b215b8455d..f751eebf69 100644 --- a/tracing-attributes/tests/instrument.rs +++ b/tracing-attributes/tests/instrument.rs @@ -20,11 +20,11 @@ fn override_everything() { #[instrument(level = Level::DEBUG, target = "my_target")] fn my_other_fn() {} - let span = span::mock() + let span = expect::span() .named("my_fn") .at_level(Level::DEBUG) .with_target("my_target"); - let span2 = span::mock() + let span2 = expect::span() .named("my_other_fn") .at_level(Level::DEBUG) .with_target("my_target"); @@ -37,7 +37,7 @@ fn override_everything() { .enter(span2.clone()) .exit(span2.clone()) .drop_span(span2) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -53,21 +53,21 @@ fn fields() { #[instrument(target = "my_target", level = "debug")] fn my_fn(arg1: usize, arg2: bool) {} - let span = span::mock() + let span = expect::span() .named("my_fn") .at_level(Level::DEBUG) .with_target("my_target"); - let span2 = span::mock() + let span2 = expect::span() .named("my_fn") .at_level(Level::DEBUG) .with_target("my_target"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&2usize) - .and(field::mock("arg2").with_value(&false)) + .and(expect::field("arg2").with_value(&false)) .only(), ), ) @@ -76,16 +76,16 @@ fn fields() { .drop_span(span) .new_span( span2.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&3usize) - .and(field::mock("arg2").with_value(&true)) + .and(expect::field("arg2").with_value(&true)) .only(), ), ) .enter(span2.clone()) .exit(span2.clone()) .drop_span(span2) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -106,17 +106,17 @@ fn skip() { #[instrument(target = "my_target", level = "debug", skip_all)] fn my_fn2(_arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {} - let span = span::mock() + let span = expect::span() .named("my_fn") .at_level(Level::DEBUG) .with_target("my_target"); - let span2 = span::mock() + let span2 = expect::span() .named("my_fn") .at_level(Level::DEBUG) .with_target("my_target"); - let span3 = span::mock() + let span3 = expect::span() .named("my_fn2") .at_level(Level::DEBUG) .with_target("my_target"); @@ -124,7 +124,7 @@ fn skip() { let (subscriber, handle) = subscriber::mock() .new_span( span.clone() - .with_field(field::mock("arg1").with_value(&2usize).only()), + .with_field(expect::field("arg1").with_value(&2usize).only()), ) .enter(span.clone()) .exit(span.clone()) @@ -132,7 +132,7 @@ fn skip() { .new_span( span2 .clone() - .with_field(field::mock("arg1").with_value(&3usize).only()), + .with_field(expect::field("arg1").with_value(&3usize).only()), ) .enter(span2.clone()) .exit(span2.clone()) @@ -141,7 +141,7 @@ fn skip() { .enter(span3.clone()) .exit(span3.clone()) .drop_span(span3) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -165,20 +165,20 @@ fn generics() { { } - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("arg1") + expect::field("arg1") .with_value(&format_args!("Foo")) - .and(field::mock("arg2").with_value(&format_args!("false"))), + .and(expect::field("arg2").with_value(&format_args!("false"))), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -198,20 +198,20 @@ fn methods() { fn my_fn(&self, arg1: usize) {} } - let span = span::mock().named("my_fn"); + let span = expect::span().named("my_fn"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone().with_field( - field::mock("self") + expect::field("self") .with_value(&format_args!("Foo")) - .and(field::mock("arg1").with_value(&42usize)), + .and(expect::field("arg1").with_value(&42usize)), ), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -229,17 +229,17 @@ fn impl_trait_return_type() { 0..x } - let span = span::mock().named("returns_impl_trait"); + let span = expect::span().named("returns_impl_trait"); let (subscriber, handle) = subscriber::mock() .new_span( span.clone() - .with_field(field::mock("x").with_value(&10usize).only()), + .with_field(expect::field("x").with_value(&10usize).only()), ) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/levels.rs b/tracing-attributes/tests/levels.rs index 94fc7e85a2..ed80dc16a6 100644 --- a/tracing-attributes/tests/levels.rs +++ b/tracing-attributes/tests/levels.rs @@ -20,22 +20,22 @@ fn named_levels() { #[instrument(level = "eRrOr")] fn error() {} let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("trace").at_level(Level::TRACE)) - .enter(span::mock().named("trace").at_level(Level::TRACE)) - .exit(span::mock().named("trace").at_level(Level::TRACE)) - .new_span(span::mock().named("debug").at_level(Level::DEBUG)) - .enter(span::mock().named("debug").at_level(Level::DEBUG)) - .exit(span::mock().named("debug").at_level(Level::DEBUG)) - .new_span(span::mock().named("info").at_level(Level::INFO)) - .enter(span::mock().named("info").at_level(Level::INFO)) - .exit(span::mock().named("info").at_level(Level::INFO)) - .new_span(span::mock().named("warn").at_level(Level::WARN)) - .enter(span::mock().named("warn").at_level(Level::WARN)) - .exit(span::mock().named("warn").at_level(Level::WARN)) - .new_span(span::mock().named("error").at_level(Level::ERROR)) - .enter(span::mock().named("error").at_level(Level::ERROR)) - .exit(span::mock().named("error").at_level(Level::ERROR)) - .done() + .new_span(expect::span().named("trace").at_level(Level::TRACE)) + .enter(expect::span().named("trace").at_level(Level::TRACE)) + .exit(expect::span().named("trace").at_level(Level::TRACE)) + .new_span(expect::span().named("debug").at_level(Level::DEBUG)) + .enter(expect::span().named("debug").at_level(Level::DEBUG)) + .exit(expect::span().named("debug").at_level(Level::DEBUG)) + .new_span(expect::span().named("info").at_level(Level::INFO)) + .enter(expect::span().named("info").at_level(Level::INFO)) + .exit(expect::span().named("info").at_level(Level::INFO)) + .new_span(expect::span().named("warn").at_level(Level::WARN)) + .enter(expect::span().named("warn").at_level(Level::WARN)) + .exit(expect::span().named("warn").at_level(Level::WARN)) + .new_span(expect::span().named("error").at_level(Level::ERROR)) + .enter(expect::span().named("error").at_level(Level::ERROR)) + .exit(expect::span().named("error").at_level(Level::ERROR)) + .only() .run_with_handle(); with_default(subscriber, || { @@ -66,22 +66,22 @@ fn numeric_levels() { #[instrument(level = 5)] fn error() {} let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("trace").at_level(Level::TRACE)) - .enter(span::mock().named("trace").at_level(Level::TRACE)) - .exit(span::mock().named("trace").at_level(Level::TRACE)) - .new_span(span::mock().named("debug").at_level(Level::DEBUG)) - .enter(span::mock().named("debug").at_level(Level::DEBUG)) - .exit(span::mock().named("debug").at_level(Level::DEBUG)) - .new_span(span::mock().named("info").at_level(Level::INFO)) - .enter(span::mock().named("info").at_level(Level::INFO)) - .exit(span::mock().named("info").at_level(Level::INFO)) - .new_span(span::mock().named("warn").at_level(Level::WARN)) - .enter(span::mock().named("warn").at_level(Level::WARN)) - .exit(span::mock().named("warn").at_level(Level::WARN)) - .new_span(span::mock().named("error").at_level(Level::ERROR)) - .enter(span::mock().named("error").at_level(Level::ERROR)) - .exit(span::mock().named("error").at_level(Level::ERROR)) - .done() + .new_span(expect::span().named("trace").at_level(Level::TRACE)) + .enter(expect::span().named("trace").at_level(Level::TRACE)) + .exit(expect::span().named("trace").at_level(Level::TRACE)) + .new_span(expect::span().named("debug").at_level(Level::DEBUG)) + .enter(expect::span().named("debug").at_level(Level::DEBUG)) + .exit(expect::span().named("debug").at_level(Level::DEBUG)) + .new_span(expect::span().named("info").at_level(Level::INFO)) + .enter(expect::span().named("info").at_level(Level::INFO)) + .exit(expect::span().named("info").at_level(Level::INFO)) + .new_span(expect::span().named("warn").at_level(Level::WARN)) + .enter(expect::span().named("warn").at_level(Level::WARN)) + .exit(expect::span().named("warn").at_level(Level::WARN)) + .new_span(expect::span().named("error").at_level(Level::ERROR)) + .enter(expect::span().named("error").at_level(Level::ERROR)) + .exit(expect::span().named("error").at_level(Level::ERROR)) + .only() .run_with_handle(); with_default(subscriber, || { @@ -112,22 +112,22 @@ fn enum_levels() { #[instrument(level = Level::ERROR)] fn error() {} let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("trace").at_level(Level::TRACE)) - .enter(span::mock().named("trace").at_level(Level::TRACE)) - .exit(span::mock().named("trace").at_level(Level::TRACE)) - .new_span(span::mock().named("debug").at_level(Level::DEBUG)) - .enter(span::mock().named("debug").at_level(Level::DEBUG)) - .exit(span::mock().named("debug").at_level(Level::DEBUG)) - .new_span(span::mock().named("info").at_level(Level::INFO)) - .enter(span::mock().named("info").at_level(Level::INFO)) - .exit(span::mock().named("info").at_level(Level::INFO)) - .new_span(span::mock().named("warn").at_level(Level::WARN)) - .enter(span::mock().named("warn").at_level(Level::WARN)) - .exit(span::mock().named("warn").at_level(Level::WARN)) - .new_span(span::mock().named("error").at_level(Level::ERROR)) - .enter(span::mock().named("error").at_level(Level::ERROR)) - .exit(span::mock().named("error").at_level(Level::ERROR)) - .done() + .new_span(expect::span().named("trace").at_level(Level::TRACE)) + .enter(expect::span().named("trace").at_level(Level::TRACE)) + .exit(expect::span().named("trace").at_level(Level::TRACE)) + .new_span(expect::span().named("debug").at_level(Level::DEBUG)) + .enter(expect::span().named("debug").at_level(Level::DEBUG)) + .exit(expect::span().named("debug").at_level(Level::DEBUG)) + .new_span(expect::span().named("info").at_level(Level::INFO)) + .enter(expect::span().named("info").at_level(Level::INFO)) + .exit(expect::span().named("info").at_level(Level::INFO)) + .new_span(expect::span().named("warn").at_level(Level::WARN)) + .enter(expect::span().named("warn").at_level(Level::WARN)) + .exit(expect::span().named("warn").at_level(Level::WARN)) + .new_span(expect::span().named("error").at_level(Level::ERROR)) + .enter(expect::span().named("error").at_level(Level::ERROR)) + .exit(expect::span().named("error").at_level(Level::ERROR)) + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/names.rs b/tracing-attributes/tests/names.rs index d97dece9a1..03e3dbfa45 100644 --- a/tracing-attributes/tests/names.rs +++ b/tracing-attributes/tests/names.rs @@ -17,10 +17,10 @@ fn custom_name_no_equals() {} #[test] fn default_name_test() { let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("default_name")) - .enter(span::mock().named("default_name")) - .exit(span::mock().named("default_name")) - .done() + .new_span(expect::span().named("default_name")) + .enter(expect::span().named("default_name")) + .exit(expect::span().named("default_name")) + .only() .run_with_handle(); with_default(subscriber, || { @@ -33,10 +33,10 @@ fn default_name_test() { #[test] fn custom_name_test() { let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("my_name")) - .enter(span::mock().named("my_name")) - .exit(span::mock().named("my_name")) - .done() + .new_span(expect::span().named("my_name")) + .enter(expect::span().named("my_name")) + .exit(expect::span().named("my_name")) + .only() .run_with_handle(); with_default(subscriber, || { @@ -49,10 +49,10 @@ fn custom_name_test() { #[test] fn custom_name_no_equals_test() { let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("my_other_name")) - .enter(span::mock().named("my_other_name")) - .exit(span::mock().named("my_other_name")) - .done() + .new_span(expect::span().named("my_other_name")) + .enter(expect::span().named("my_other_name")) + .exit(expect::span().named("my_other_name")) + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/parents.rs b/tracing-attributes/tests/parents.rs index 7069b98ea5..d4559415d9 100644 --- a/tracing-attributes/tests/parents.rs +++ b/tracing-attributes/tests/parents.rs @@ -14,8 +14,8 @@ where #[test] fn default_parent_test() { - let contextual_parent = span::mock().named("contextual_parent"); - let child = span::mock().named("with_default_parent"); + let contextual_parent = expect::span().named("contextual_parent"); + let child = expect::span().named("with_default_parent"); let (subscriber, handle) = subscriber::mock() .new_span( @@ -42,7 +42,7 @@ fn default_parent_test() { .enter(child.clone()) .exit(child) .exit(contextual_parent) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -60,9 +60,9 @@ fn default_parent_test() { #[test] fn explicit_parent_test() { - let contextual_parent = span::mock().named("contextual_parent"); - let explicit_parent = span::mock().named("explicit_parent"); - let child = span::mock().named("with_explicit_parent"); + let contextual_parent = expect::span().named("contextual_parent"); + let explicit_parent = expect::span().named("explicit_parent"); + let child = expect::span().named("with_explicit_parent"); let (subscriber, handle) = subscriber::mock() .new_span( @@ -86,7 +86,7 @@ fn explicit_parent_test() { .enter(child.clone()) .exit(child) .exit(contextual_parent) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-attributes/tests/ret.rs b/tracing-attributes/tests/ret.rs index f56c80baaf..90bd9e185d 100644 --- a/tracing-attributes/tests/ret.rs +++ b/tracing-attributes/tests/ret.rs @@ -19,18 +19,18 @@ fn ret_with_target() -> i32 { #[test] fn test() { - let span = span::mock().named("ret"); + let span = expect::span().named("ret"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::INFO), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret); @@ -40,7 +40,7 @@ fn test() { #[test] fn test_custom_target() { let filter: EnvFilter = "my_target=info".parse().expect("filter should parse"); - let span = span::mock() + let span = expect::span() .named("ret_with_target") .with_target("my_target"); @@ -48,14 +48,14 @@ fn test_custom_target() { .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::INFO) .with_target("my_target"), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); let subscriber = subscriber.with(filter); @@ -71,18 +71,18 @@ fn ret_warn() -> i32 { #[test] fn test_warn() { - let span = span::mock().named("ret_warn"); + let span = expect::span().named("ret_warn"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::WARN), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret_warn); @@ -98,23 +98,23 @@ fn ret_mut(a: &mut i32) -> i32 { #[test] fn test_mut() { - let span = span::mock().named("ret_mut"); + let span = expect::span().named("ret_mut"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("a").with_value(&tracing::field::display(2))) + expect::event() + .with_fields(expect::field("a").with_value(&tracing::field::display(2))) .at_level(Level::INFO), ) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(2))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(2))) .at_level(Level::INFO), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || ret_mut(&mut 1)); @@ -128,20 +128,20 @@ async fn ret_async() -> i32 { #[test] fn test_async() { - let span = span::mock().named("ret_async"); + let span = expect::span().named("ret_async"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::INFO), ) .exit(span.clone()) .enter(span.clone()) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || block_on_future(async { ret_async().await })); @@ -155,18 +155,18 @@ fn ret_impl_type() -> impl Copy { #[test] fn test_impl_type() { - let span = span::mock().named("ret_impl_type"); + let span = expect::span().named("ret_impl_type"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::INFO), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret_impl_type); @@ -180,18 +180,18 @@ fn ret_display() -> i32 { #[test] fn test_dbg() { - let span = span::mock().named("ret_display"); + let span = expect::span().named("ret_display"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::display(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::display(42))) .at_level(Level::INFO), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret_display); @@ -205,14 +205,14 @@ fn ret_and_err() -> Result { #[test] fn test_ret_and_err() { - let span = span::mock().named("ret_and_err"); + let span = expect::span().named("ret_and_err"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() + expect::event() .with_fields( - field::mock("error") + expect::field("error") .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err())) .only(), ) @@ -220,7 +220,7 @@ fn test_ret_and_err() { ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || ret_and_err().ok()); @@ -234,14 +234,14 @@ fn ret_and_ok() -> Result { #[test] fn test_ret_and_ok() { - let span = span::mock().named("ret_and_ok"); + let span = expect::span().named("ret_and_ok"); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() + expect::event() .with_fields( - field::mock("return") + expect::field("return") .with_value(&tracing::field::debug(u8::try_from(123).unwrap())) .only(), ) @@ -249,7 +249,7 @@ fn test_ret_and_ok() { ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, || ret_and_ok().ok()); @@ -263,18 +263,18 @@ fn ret_warn_info() -> i32 { #[test] fn test_warn_info() { - let span = span::mock().named("ret_warn_info").at_level(Level::WARN); + let span = expect::span().named("ret_warn_info").at_level(Level::WARN); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::INFO), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret_warn_info); @@ -288,18 +288,18 @@ fn ret_dbg_warn() -> i32 { #[test] fn test_dbg_warn() { - let span = span::mock().named("ret_dbg_warn").at_level(Level::INFO); + let span = expect::span().named("ret_dbg_warn").at_level(Level::INFO); let (subscriber, handle) = subscriber::mock() .new_span(span.clone()) .enter(span.clone()) .event( - event::mock() - .with_fields(field::mock("return").with_value(&tracing::field::debug(42))) + expect::event() + .with_fields(expect::field("return").with_value(&tracing::field::debug(42))) .at_level(Level::WARN), ) .exit(span.clone()) .drop_span(span) - .done() + .only() .run_with_handle(); with_default(subscriber, ret_dbg_warn); diff --git a/tracing-attributes/tests/targets.rs b/tracing-attributes/tests/targets.rs index 363f628f31..0e70287d3e 100644 --- a/tracing-attributes/tests/targets.rs +++ b/tracing-attributes/tests/targets.rs @@ -24,36 +24,36 @@ mod my_mod { fn default_targets() { let (subscriber, handle) = subscriber::mock() .new_span( - span::mock() + expect::span() .named("default_target") .with_target(module_path!()), ) .enter( - span::mock() + expect::span() .named("default_target") .with_target(module_path!()), ) .exit( - span::mock() + expect::span() .named("default_target") .with_target(module_path!()), ) .new_span( - span::mock() + expect::span() .named("default_target") .with_target(my_mod::MODULE_PATH), ) .enter( - span::mock() + expect::span() .named("default_target") .with_target(my_mod::MODULE_PATH), ) .exit( - span::mock() + expect::span() .named("default_target") .with_target(my_mod::MODULE_PATH), ) - .done() + .only() .run_with_handle(); with_default(subscriber, || { @@ -67,25 +67,37 @@ fn default_targets() { #[test] fn custom_targets() { let (subscriber, handle) = subscriber::mock() - .new_span(span::mock().named("custom_target").with_target("my_target")) - .enter(span::mock().named("custom_target").with_target("my_target")) - .exit(span::mock().named("custom_target").with_target("my_target")) .new_span( - span::mock() + expect::span() + .named("custom_target") + .with_target("my_target"), + ) + .enter( + expect::span() + .named("custom_target") + .with_target("my_target"), + ) + .exit( + expect::span() + .named("custom_target") + .with_target("my_target"), + ) + .new_span( + expect::span() .named("custom_target") .with_target("my_other_target"), ) .enter( - span::mock() + expect::span() .named("custom_target") .with_target("my_other_target"), ) .exit( - span::mock() + expect::span() .named("custom_target") .with_target("my_other_target"), ) - .done() + .only() .run_with_handle(); with_default(subscriber, || { diff --git a/tracing-core/src/dispatcher.rs b/tracing-core/src/dispatcher.rs index 32632abdc5..de02afb790 100644 --- a/tracing-core/src/dispatcher.rs +++ b/tracing-core/src/dispatcher.rs @@ -518,8 +518,8 @@ impl Dispatch { } } - /// Registers a new callsite with this collector, returning whether or not - /// the collector is interested in being notified about the callsite. + /// Registers a new callsite with this subscriber, returning whether or not + /// the subscriber is interested in being notified about the callsite. /// /// This calls the [`register_callsite`] function on the [`Subscriber`] /// that this `Dispatch` forwards to. diff --git a/tracing-core/src/field.rs b/tracing-core/src/field.rs index 84936c51a0..90c4eaa85d 100644 --- a/tracing-core/src/field.rs +++ b/tracing-core/src/field.rs @@ -1,8 +1,8 @@ //! `Span` and `Event` key-value data. //! -//! Spans and events may be annotated with key-value data, referred to as known -//! as _fields_. These fields consist of a mapping from a key (corresponding to -//! a `&str` but represented internally as an array index) to a [`Value`]. +//! Spans and events may be annotated with key-value data, known as _fields_. +//! These fields consist of a mapping from a key (corresponding to a `&str` but +//! represented internally as an array index) to a [`Value`]. //! //! # `Value`s and `Subscriber`s //! @@ -470,6 +470,10 @@ macro_rules! impl_one_value { impl $crate::sealed::Sealed for $value_ty {} impl $crate::field::Value for $value_ty { fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) { + // `op` is always a function; the closure is used because + // sometimes there isn't a real function corresponding to that + // operation. the clippy warning is not that useful here. + #[allow(clippy::redundant_closure_call)] visitor.$record(key, $op(*self)) } } @@ -485,6 +489,10 @@ macro_rules! impl_one_value { impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {} impl $crate::field::Value for ty_to_nonzero!($value_ty) { fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) { + // `op` is always a function; the closure is used because + // sometimes there isn't a real function corresponding to that + // operation. the clippy warning is not that useful here. + #[allow(clippy::redundant_closure_call)] visitor.$record(key, $op(self.get())) } } @@ -871,9 +879,6 @@ impl FieldSet { } /// Returns a new `ValueSet` with entries for this `FieldSet`'s values. - /// - /// Note that a `ValueSet` may not be constructed with arrays of over 32 - /// elements. #[doc(hidden)] pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> where @@ -1072,28 +1077,10 @@ impl<'a> fmt::Display for ValueSet<'a> { mod private { use super::*; - /// Marker trait implemented by arrays which are of valid length to - /// construct a `ValueSet`. - /// - /// `ValueSet`s may only be constructed from arrays containing 32 or fewer - /// elements, to ensure the array is small enough to always be allocated on the - /// stack. This trait is only implemented by arrays of an appropriate length, - /// ensuring that the correct size arrays are used at compile-time. + /// Restrictions on `ValueSet` lengths were removed in #2508 but this type remains for backwards compatibility. pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {} -} - -macro_rules! impl_valid_len { - ( $( $len:tt ),+ ) => { - $( - impl<'a> private::ValidLen<'a> for - [(&'a Field, Option<&'a (dyn Value + 'a)>); $len] {} - )+ - } -} -impl_valid_len! { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + impl<'a, const N: usize> ValidLen<'a> for [(&'a Field, Option<&'a (dyn Value + 'a)>); N] {} } #[cfg(test)] @@ -1102,8 +1089,9 @@ mod test { use crate::metadata::{Kind, Level, Metadata}; use crate::stdlib::{borrow::ToOwned, string::String}; - struct TestCallsite1; - static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1; + // Make sure TEST_CALLSITE_* have non-zero size, so they can't be located at the same address. + struct TestCallsite1(u8); + static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1(0); static TEST_META_1: Metadata<'static> = metadata! { name: "field_test1", target: module_path!(), @@ -1123,8 +1111,8 @@ mod test { } } - struct TestCallsite2; - static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2; + struct TestCallsite2(u8); + static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2(0); static TEST_META_2: Metadata<'static> = metadata! { name: "field_test2", target: module_path!(), diff --git a/tracing-core/src/lib.rs b/tracing-core/src/lib.rs index f5de4eeba9..d43a6b8b04 100644 --- a/tracing-core/src/lib.rs +++ b/tracing-core/src/lib.rs @@ -243,9 +243,9 @@ macro_rules! metadata { $name, $target, $level, - Some(file!()), - Some(line!()), - Some(module_path!()), + ::core::option::Option::Some(file!()), + ::core::option::Option::Some(line!()), + ::core::option::Option::Some(module_path!()), $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)), $kind, ) diff --git a/tracing-flame/src/lib.rs b/tracing-flame/src/lib.rs index 5805850555..a4731dd154 100644 --- a/tracing-flame/src/lib.rs +++ b/tracing-flame/src/lib.rs @@ -233,7 +233,7 @@ impl Default for Config { empty_samples: true, threads_collapsed: false, module_path: true, - file_and_line: true, + file_and_line: false, } } } @@ -404,7 +404,7 @@ where if let Some(second) = first.parent() { for parent in second.scope().from_root() { - stack += "; "; + stack += ";"; write(&mut stack, parent, &self.config) .expect("expected: write to String never fails"); } @@ -446,7 +446,7 @@ where } for parent in first.scope().from_root() { - stack += "; "; + stack += ";"; expect!( write(&mut stack, parent, &self.config), "expected: write to String never fails" diff --git a/tracing-futures/src/lib.rs b/tracing-futures/src/lib.rs index 8065175d28..c79e748a0d 100644 --- a/tracing-futures/src/lib.rs +++ b/tracing-futures/src/lib.rs @@ -634,14 +634,14 @@ mod tests { #[test] fn future_enter_exit_is_reasonable() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) - .done() + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) + .only() .run_with_handle(); with_default(subscriber, || { PollN::new_ok(2) @@ -655,14 +655,14 @@ mod tests { #[test] fn future_error_ends_span() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) - .done() + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) + .only() .run_with_handle(); with_default(subscriber, || { PollN::new_err(2) @@ -677,17 +677,17 @@ mod tests { #[test] fn stream_enter_exit_is_reasonable() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) .run_with_handle(); with_default(subscriber, || { stream::iter_ok::<_, ()>(&[1, 2, 3]) @@ -702,15 +702,15 @@ mod tests { // #[test] // fn span_follows_future_onto_threadpool() { // let (subscriber, handle) = subscriber::mock() - // .enter(span::mock().named("a")) - // .enter(span::mock().named("b")) - // .exit(span::mock().named("b")) - // .enter(span::mock().named("b")) - // .exit(span::mock().named("b")) - // .drop_span(span::mock().named("b")) - // .exit(span::mock().named("a")) - // .drop_span(span::mock().named("a")) - // .done() + // .enter(expect::span().named("a")) + // .enter(expect::span().named("b")) + // .exit(expect::span().named("b")) + // .enter(expect::span().named("b")) + // .exit(expect::span().named("b")) + // .drop_span(expect::span().named("b")) + // .exit(expect::span().named("a")) + // .drop_span(expect::span().named("a")) + // .only() // .run_with_handle(); // let mut runtime = tokio::runtime::Runtime::new().unwrap(); // with_default(subscriber, || { @@ -740,15 +740,15 @@ mod tests { #[test] fn stream_enter_exit_is_reasonable() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) .run_with_handle(); with_default(subscriber, || { Instrument::instrument(stream::iter(&[1, 2, 3]), tracing::trace_span!("foo")) @@ -762,13 +762,13 @@ mod tests { #[test] fn sink_enter_exit_is_reasonable() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) .run_with_handle(); with_default(subscriber, || { Instrument::instrument(sink::drain(), tracing::trace_span!("foo")) diff --git a/tracing-futures/tests/std_future.rs b/tracing-futures/tests/std_future.rs index 8bc31149c7..4f29fd73cd 100644 --- a/tracing-futures/tests/std_future.rs +++ b/tracing-futures/tests/std_future.rs @@ -8,14 +8,14 @@ use tracing_mock::*; #[test] fn enter_exit_is_reasonable() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) - .done() + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) + .only() .run_with_handle(); with_default(subscriber, || { let future = PollN::new_ok(2).instrument(tracing::span!(Level::TRACE, "foo")); @@ -27,14 +27,14 @@ fn enter_exit_is_reasonable() { #[test] fn error_ends_span() { let (subscriber, handle) = subscriber::mock() - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) - .done() + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) + .only() .run_with_handle(); with_default(subscriber, || { let future = PollN::new_err(2).instrument(tracing::span!(Level::TRACE, "foo")); @@ -66,17 +66,17 @@ fn span_on_drop() { } let subscriber = subscriber::mock() - .enter(span::mock().named("foo")) - .event(event::mock().at_level(Level::INFO)) - .exit(span::mock().named("foo")) - .enter(span::mock().named("foo")) - .exit(span::mock().named("foo")) - .drop_span(span::mock().named("foo")) - .enter(span::mock().named("bar")) - .event(event::mock().at_level(Level::INFO)) - .exit(span::mock().named("bar")) - .drop_span(span::mock().named("bar")) - .done() + .enter(expect::span().named("foo")) + .event(expect::event().at_level(Level::INFO)) + .exit(expect::span().named("foo")) + .enter(expect::span().named("foo")) + .exit(expect::span().named("foo")) + .drop_span(expect::span().named("foo")) + .enter(expect::span().named("bar")) + .event(expect::event().at_level(Level::INFO)) + .exit(expect::span().named("bar")) + .drop_span(expect::span().named("bar")) + .only() .run(); with_default(subscriber, || { diff --git a/tracing-journald/src/lib.rs b/tracing-journald/src/lib.rs index ac816058ca..fc7263086b 100644 --- a/tracing-journald/src/lib.rs +++ b/tracing-journald/src/lib.rs @@ -83,6 +83,7 @@ pub struct Layer { socket: UnixDatagram, field_prefix: Option, syslog_identifier: String, + additional_fields: Vec, } #[cfg(unix)] @@ -107,6 +108,7 @@ impl Layer { .map(|n| n.to_string_lossy().into_owned()) // If we fail to get the name of the current executable fall back to an empty string. .unwrap_or_else(String::new), + additional_fields: Vec::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. @@ -148,6 +150,40 @@ impl Layer { self } + /// Adds fields that will get be passed to journald with every log entry. + /// + /// The input values of this function are interpreted as `(field, value)` pairs. + /// + /// This can for example be used to configure the syslog facility. + /// See [Journal Fields](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) + /// and [journalctl](https://www.freedesktop.org/software/systemd/man/journalctl.html) + /// for more information. + /// + /// Fields specified using this method will be added to the journald + /// message alongside fields generated from the event's fields, its + /// metadata, and the span context. If the name of a field provided using + /// this method is the same as the name of a field generated by the + /// layer, both fields will be sent to journald. + /// + /// ```no_run + /// # use tracing_journald::Layer; + /// let layer = Layer::new() + /// .unwrap() + /// .with_custom_fields([("SYSLOG_FACILITY", "17")]); + /// ``` + /// + pub fn with_custom_fields, U: AsRef<[u8]>>( + mut self, + fields: impl IntoIterator, + ) -> Self { + for (name, value) in fields { + put_field_length_encoded(&mut self.additional_fields, name.as_ref(), |buf| { + buf.extend_from_slice(value.as_ref()) + }) + } + self + } + /// Returns the syslog identifier in use. pub fn syslog_identifier(&self) -> &str { &self.syslog_identifier @@ -255,6 +291,7 @@ where put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| { write!(buf, "{}", self.syslog_identifier).unwrap() }); + buf.extend_from_slice(&self.additional_fields); event.record(&mut EventVisitor::new( &mut buf, diff --git a/tracing-journald/src/socket.rs b/tracing-journald/src/socket.rs index bba53d8658..6803bf34e0 100644 --- a/tracing-journald/src/socket.rs +++ b/tracing-journald/src/socket.rs @@ -68,7 +68,7 @@ pub fn send_one_fd_to>(socket: &UnixDatagram, fd: RawFd, path: P) msg.msg_control = unsafe { cmsg_buffer.buffer.as_mut_ptr() as _ }; msg.msg_controllen = unsafe { CMSG_SPACE(size_of::() as _) as _ }; - let mut cmsg: &mut cmsghdr = + let cmsg: &mut cmsghdr = unsafe { CMSG_FIRSTHDR(&msg).as_mut() }.expect("Control message buffer exhausted"); cmsg.cmsg_level = SOL_SOCKET; diff --git a/tracing-journald/tests/journal.rs b/tracing-journald/tests/journal.rs index 7cbcd24d15..c2f3010879 100644 --- a/tracing-journald/tests/journal.rs +++ b/tracing-journald/tests/journal.rs @@ -238,6 +238,28 @@ fn simple_metadata() { }); } +#[test] +fn journal_fields() { + let sub = Layer::new() + .unwrap() + .with_field_prefix(None) + .with_custom_fields([("SYSLOG_FACILITY", "17")]) + .with_custom_fields([("ABC", "dEf"), ("XYZ", "123")]); + with_journald_layer(sub, || { + info!(test.name = "journal_fields", "Hello World"); + + let message = retry_read_one_line_from_journal("journal_fields"); + assert_eq!(message["MESSAGE"], "Hello World"); + assert_eq!(message["PRIORITY"], "5"); + assert_eq!(message["TARGET"], "journal"); + assert_eq!(message["SYSLOG_FACILITY"], "17"); + assert_eq!(message["ABC"], "dEf"); + assert_eq!(message["XYZ"], "123"); + assert!(message["CODE_FILE"].as_text().is_some()); + assert!(message["CODE_LINE"].as_text().is_some()); + }); +} + #[test] fn span_metadata() { with_journald(|| { diff --git a/tracing-log/src/lib.rs b/tracing-log/src/lib.rs index 768d4f6922..d2637545c1 100644 --- a/tracing-log/src/lib.rs +++ b/tracing-log/src/lib.rs @@ -307,9 +307,9 @@ macro_rules! log_cs { "log event", "log", $level, - None, - None, - None, + ::core::option::Option::None, + ::core::option::Option::None, + ::core::option::Option::None, field::FieldSet::new(FIELD_NAMES, identify_callsite!(&$cs)), Kind::EVENT, ); diff --git a/tracing-mock/Cargo.toml b/tracing-mock/Cargo.toml index 2e060df78c..5cfca82b12 100644 --- a/tracing-mock/Cargo.toml +++ b/tracing-mock/Cargo.toml @@ -18,9 +18,9 @@ rust-version = "1.56.0" publish = false [dependencies] -tracing = { path = "../tracing", version = "0.1.35", default-features = false } +tracing = { path = "../tracing", version = "0.1.35", features = ["std", "attributes"], default-features = false } tracing-core = { path = "../tracing-core", version = "0.1.28", default-features = false } -tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, optional = true } +tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry"], optional = true } tokio-test = { version = "0.4.2", optional = true } # Fix minimal-versions; tokio-test fails with otherwise acceptable 0.1.0 diff --git a/tracing-mock/README.md b/tracing-mock/README.md new file mode 100644 index 0000000000..c3adff3dab --- /dev/null +++ b/tracing-mock/README.md @@ -0,0 +1,176 @@ +![Tracing — Structured, application-level diagnostics][splash] + +[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg + +# tracing-mock + +Utilities for testing [`tracing`][tracing] and crates that uses it. + +[![Documentation (master)][docs-master-badge]][docs-master-url] +[![MIT licensed][mit-badge]][mit-url] +[![Build Status][actions-badge]][actions-url] +[![Discord chat][discord-badge]][discord-url] + +[Documentation][docs-master-url] | [Chat][discord-url] + +[docs-master-badge]: https://img.shields.io/badge/docs-master-blue +[docs-master-url]: https://tracing-rs.netlify.com/tracing_mock +[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-url]: https://github.com/tokio-rs/tracing/blob/master/tracing-mock/LICENSE +[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg +[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI +[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white +[discord-url]: https://discord.gg/EeF3cQw + +## Overview + +[`tracing`] is a framework for instrumenting Rust programs to collect +structured, event-based diagnostic information. `tracing-mock` provides +tools for making assertions about what `tracing` diagnostics are emitted +by code under test. + +*Compiler support: [requires `rustc` 1.56+][msrv]* + +[msrv]: #supported-rust-versions + +## Usage + +`tracing-mock` crate provides a mock +[`Collector`](https://tracing-rs.netlify.app/tracing/#collectors) +that allows asserting on the order and contents of +[spans](https://tracing-rs.netlify.app/tracing/#spans) and +[events](https://tracing-rs.netlify.app/tracing/#events). + +As `tracing-mock` isn't available on [crates.io](https://crates.io/) +yet, you must import it via git. When using `tracing-mock` with the +`tracing` `0.1` ecosystem, it is important that you also override the +source of any `tracing` crates that are transient dependencies. For +example, the `Cargo.toml` for your test crate could contain: + +```toml +[dependencies] +lib-under-test = "1.0" # depends on `tracing` + +[dev-dependencies] +tracing-mock = { git = "https://github.com/tokio-rs/tracing", branch = "v0.1.x", version = "0.1" } +tracing = { git = "https://github.com/tokio-rs/tracing", branch = "v0.1.x", version = "0.1" } + +[patch.crates-io] +tracing = { git = "https://github.com/tokio-rs/tracing", branch = "v0.1.x" } +tracing-core = { git = "https://github.com/tokio-rs/tracing", branch = "v0.1.x" } +``` + +## Examples + +The following examples are for the `master` branch. For examples that +will work with `tracing` from [crates.io], please check the +[v0.1.x](https://github.com/tokio-rs/tracing/tree/v0.1.x/tracing-mock) +branch. + +Below is an example that checks that an event contains a message: + +```rust +use tracing::subscriber::with_default; +use tracing_mock::{subscriber, expect, field}; + +fn yak_shaving() { + tracing::info!("preparing to shave yaks"); +} + +let (subscriber, handle) = subscriber::mock() + .event(expect::event().with_fields(field::msg("preparing to shave yaks"))) + .only() + .run_with_handle(); + +with_default(subscriber, || { + yak_shaving(); +}); + +handle.assert_finished(); + +``` + +Below is a slightly more complex example. `tracing-mock` asserts that, in order: +- a span is created with a single field/value pair +- the span is entered +- an event is created with the field `number_of_yaks`, a corresponding + value of 3, and the message "preparing to shave yaks", and nothing else +- an event is created with the field `all_yaks_shaved`, a corresponding value + of `true`, and the message "yak shaving completed" +- the span is exited +- no further traces are received + +```rust +use tracing::subscriber::with_default; +use tracing_mock::{subscriber, expect, field}; + +#[tracing::instrument] +fn yak_shaving(number_of_yaks: u32) { + tracing::info!(number_of_yaks, "preparing to shave yaks"); + + let number_shaved = number_of_yaks; // shave_all + tracing::info!( + all_yaks_shaved = number_shaved == number_of_yaks, + "yak shaving completed." + ); +} + +let yak_count: u32 = 3; +let span = expect::span().named("yak_shaving"); + +let (subscriber, handle) = subscriber::mock() + .new_span( + span.clone() + .with_field(expect::field("number_of_yaks").with_value(&yak_count).only()), + ) + .enter(span.clone()) + .event( + expect::event().with_fields( + expect::field("number_of_yaks") + .with_value(&yak_count) + .and(field::msg("preparing to shave yaks")) + .only(), + ), + ) + .event( + expect::event().with_fields( + expect::field("all_yaks_shaved") + .with_value(&true) + .and(field::msg("yak shaving completed.")) + .only(), + ), + ) + .exit(span.clone()) + .only() + .run_with_handle(); + +with_default(subscriber, || { + yak_shaving(yak_count); +}); + +handle.assert_finished(); +``` + +## Supported Rust Versions + +Tracing is built against the latest stable release. The minimum supported +version is 1.56. The current Tracing version is not guaranteed to build on Rust +versions earlier than the minimum supported version. + +Tracing follows the same compiler support policies as the rest of the Tokio +project. The current stable Rust compiler and the three most recent minor +versions before it will always be supported. For example, if the current stable +compiler version is 1.69, the minimum supported version will not be increased +past 1.66, three minor versions prior. Increasing the minimum supported compiler +version is not considered a semver breaking change as long as doing so complies +with this policy. + +## License + +This project is licensed under the [MIT license][mit-url]. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Tracing by you, shall be licensed as MIT, without any additional +terms or conditions. \ No newline at end of file diff --git a/tracing-mock/src/event.rs b/tracing-mock/src/event.rs index 9e57864964..103d663605 100644 --- a/tracing-mock/src/event.rs +++ b/tracing-mock/src/event.rs @@ -1,37 +1,77 @@ +//! An [`ExpectedEvent`] defines an event to be matched by the mock +//! subscriber API in the [`subscriber`] module. +//! +//! The expected event should be created with [`expect::event`] and a +//! chain of method calls to describe the assertions we wish to make +//! about the event. +//! +//! # Examples +//! +//! ``` +//! use tracing::subscriber::with_default; +//! use tracing_mock::{expect, subscriber}; +//! +//! let event = expect::event() +//! .at_level(tracing::Level::INFO) +//! .with_fields(expect::field("field.name").with_value(&"field_value")); +//! +//! let (subscriber, handle) = subscriber::mock() +//! .event(event) +//! .run_with_handle(); +//! +//! with_default(subscriber, || { +//! tracing::info!(field.name = "field_value"); +//! }); +//! +//! handle.assert_finished(); +//! ``` +//! +//! [`subscriber`]: mod@crate::subscriber +//! [`expect::event`]: fn@crate::expect::event #![allow(missing_docs)] -use super::{field, metadata, span, Parent}; +use super::{expect, field, metadata::ExpectedMetadata, span, Parent}; use std::fmt; -/// A mock event. +/// An expected event. /// -/// This is intended for use with the mock subscriber API in the -/// `subscriber` module. +/// For a detailed description and examples, see the documentation for +/// the methods and the [`event`] module. +/// +/// [`event`]: mod@crate::event #[derive(Default, Eq, PartialEq)] -pub struct MockEvent { - pub fields: Option, - in_spans: Vec, - pub(crate) parent: Option, - metadata: metadata::Expect, -} - -pub fn mock() -> MockEvent { - MockEvent { - ..Default::default() - } +pub struct ExpectedEvent { + pub(super) fields: Option, + pub(super) parent: Option, + pub(super) in_spans: Option>, + pub(super) metadata: ExpectedMetadata, } -pub fn msg(message: impl fmt::Display) -> MockEvent { - mock().with_fields(field::msg(message)) +pub fn msg(message: impl fmt::Display) -> ExpectedEvent { + expect::event().with_fields(field::msg(message)) } -impl MockEvent { +impl ExpectedEvent { + /// Sets a name to expect when matching an event. + /// + /// By default, an event's name takes takes the form: + /// `event :` where `` and `` refer to the + /// location in the source code where the event was generated. + /// + /// To override the name of an event, it has to be constructed + /// directly, rather than by using the `tracing` crate's macros. + /// + /// In general, there are not many use cases for expecting an + /// event with a particular name, as the value includes the file + /// name and line number. Assertions about event names are + /// therefore quite fragile, since they will change as the source + /// code is modified. pub fn named(self, name: I) -> Self where I: Into, { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { name: Some(name.into()), ..self.metadata }, @@ -39,9 +79,62 @@ impl MockEvent { } } + /// Adds fields to expect when matching an event. + /// + /// If an event is recorded with fields that do not match the provided + /// [`ExpectedFields`], this expectation will fail. + /// + /// If the provided field is not present on the recorded event, or + /// if the value for that field is different, then the expectation + /// will fail. + /// + /// More information on the available validations is available in + /// the [`ExpectedFields`] documentation. + /// + /// # Examples + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_fields(expect::field("field.name").with_value(&"field_value")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(field.name = "field_value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// A different field value will cause the expectation to fail: + /// + /// ```should_panic + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_fields(expect::field("field.name").with_value(&"field_value")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(field.name = "different_field_value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`ExpectedFields`]: struct@crate::field::ExpectedFields pub fn with_fields(self, fields: I) -> Self where - I: Into, + I: Into, { Self { fields: Some(fields.into()), @@ -49,9 +142,54 @@ impl MockEvent { } } + /// Sets the [`Level`](tracing::Level) to expect when matching an event. + /// + /// If an event is recorded at a different level, this expectation + /// will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .at_level(tracing::Level::WARN); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::warn!("this message is bad news"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// Expecting an event at `INFO` level will fail if the event is + /// recorded at any other level: + /// + /// ```should_panic + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .at_level(tracing::Level::INFO); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::warn!("this message is bad news"); + /// }); + /// + /// handle.assert_finished(); + /// ``` pub fn at_level(self, level: tracing::Level) -> Self { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { level: Some(level), ..self.metadata }, @@ -59,12 +197,55 @@ impl MockEvent { } } + /// Sets the target to expect when matching events. + /// + /// If an event is recorded with a different target, this expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_target("some_target"); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(target: "some_target", field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// The test will fail if the target is different: + /// + /// ```should_panic + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_target("some_target"); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(target: "a_different_target", field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` pub fn with_target(self, target: I) -> Self where I: Into, { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { target: Some(target.into()), ..self.metadata }, @@ -72,7 +253,91 @@ impl MockEvent { } } - pub fn with_explicit_parent(self, parent: Option<&str>) -> MockEvent { + /// Configures this `ExpectedEvent` to expect an explicit parent span + /// when matching events or to be an explicit root. + /// + /// An _explicit_ parent span is one passed to the `span!` macro in the + /// `parent:` field. + /// + /// If `Some("parent_name")` is passed to `with_explicit_parent` then + /// the provided string is the name of the parent span to expect. + /// + /// To expect that an event is recorded with `parent: None`, `None` + /// can be passed to `with_explicit_parent` instead. + /// + /// If an event is recorded without an explicit parent, or if the + /// explicit parent has a different name, this expectation will + /// fail. + /// + /// # Examples + /// + /// The explicit parent is matched by name: + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_explicit_parent(Some("parent_span")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// let parent = tracing::info_span!("parent_span"); + /// tracing::info!(parent: parent.id(), field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// In the following example, we expect that the matched event is + /// an explicit root: + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_explicit_parent(None); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(parent: None, field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// In the example below, the expectation fails because the + /// event is contextually (rather than explicitly) within the span + /// `parent_span`: + /// + /// ```should_panic + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_explicit_parent(Some("parent_span")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// let parent = tracing::info_span!("parent_span"); + /// let _guard = parent.enter(); + /// tracing::info!(field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn with_explicit_parent(self, parent: Option<&str>) -> ExpectedEvent { let parent = match parent { Some(name) => Parent::Explicit(name.into()), None => Parent::ExplicitRoot, @@ -83,7 +348,213 @@ impl MockEvent { } } - pub fn check( + /// Configures this `ExpectedEvent` to match an event with a + /// contextually-determined parent span. + /// + /// The provided string is the name of the parent span to expect. + /// To expect that the event is a contextually-determined root, pass + /// `None` instead. + /// + /// To expect an event with an explicit parent span, use + /// [`ExpectedEvent::with_explicit_parent`]. + /// + /// If an event is recorded which is not inside a span, has an explicitly + /// overridden parent span, or with a differently-named span as its + /// parent, this expectation will fail. + /// + /// # Examples + /// + /// The explicit parent is matched by name: + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_contextual_parent(Some("parent_span")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// let parent = tracing::info_span!("parent_span"); + /// let _guard = parent.enter(); + /// tracing::info!(field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// Matching an event recorded outside of a span: + /// + /// ``` + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_contextual_parent(None); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// tracing::info!(field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// In the example below, the expectation fails because the + /// event is recorded with an explicit parent: + /// + /// ```should_panic + /// use tracing::subscriber::with_default; + /// use tracing_mock::{subscriber, expect}; + /// + /// let event = expect::event() + /// .with_contextual_parent(Some("parent_span")); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(subscriber, || { + /// let parent = tracing::info_span!("parent_span"); + /// tracing::info!(parent: parent.id(), field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn with_contextual_parent(self, parent: Option<&str>) -> ExpectedEvent { + let parent = match parent { + Some(name) => Parent::Contextual(name.into()), + None => Parent::ContextualRoot, + }; + Self { + parent: Some(parent), + ..self + } + } + + /// Validates that the event is emitted within the scope of the + /// provided `spans`. + /// + /// The spans must be provided reverse hierarchy order, so the + /// closest span to the event would be first, followed by its + /// parent, and so on. + /// + /// If the spans provided do not match the hierarchy of the + /// recorded event, the expectation will fail. + /// + /// **Note**: This validation currently only works with a + /// [`MockLayer`]. If used with a [`MockSubscriber`], the + /// expectation will fail directly as it is unimplemented. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let event = expect::event().in_scope([ + /// expect::span().named("parent_span"), + /// expect::span().named("grandparent_span") + /// ]); + /// + /// let (layer, handle) = layer::mock() + /// .enter(expect::span()) + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// let grandparent = tracing::info_span!("grandparent_span"); + /// let _gp_guard = grandparent.enter(); + /// let parent = tracing::info_span!("parent_span"); + /// let _p_guard = parent.enter(); + /// tracing::info!(field = &"value"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// The scope must match exactly, otherwise the expectation will fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let event = expect::event().in_scope([ + /// expect::span().named("parent_span"), + /// expect::span().named("grandparent_span") + /// ]); + /// + /// let (layer, handle) = layer::mock() + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// let parent = tracing::info_span!("parent_span"); + /// let _p_guard = parent.enter(); + /// tracing::info!(field = &"value"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// It is also possible to test that an event has no parent spans + /// by passing `None` to `in_scope`. If the event is within a + /// span, the test will fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let event = expect::event().in_scope(None); + /// + /// let (layer, handle) = layer::mock() + /// .enter(expect::span()) + /// .event(event) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// let parent = tracing::info_span!("parent_span"); + /// let _guard = parent.enter(); + /// tracing::info!(field = &"value"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`MockLayer`]: struct@crate::layer::MockLayer + /// [`MockSubscriber`]: struct@crate::subscriber::MockSubscriber + #[cfg(feature = "tracing-subscriber")] + pub fn in_scope(self, spans: impl IntoIterator) -> Self { + Self { + in_spans: Some(spans.into_iter().collect()), + ..self + } + } + + /// Provides access to the expected scope (spans) for this expected + /// event. + #[cfg(feature = "tracing-subscriber")] + pub(crate) fn scope_mut(&mut self) -> Option<&mut [span::ExpectedSpan]> { + self.in_spans.as_mut().map(|s| &mut s[..]) + } + + pub(crate) fn check( &mut self, event: &tracing::Event<'_>, get_parent_name: impl FnOnce() -> Option, @@ -116,26 +587,15 @@ impl MockEvent { ) } } - - pub fn in_scope(self, spans: impl IntoIterator) -> Self { - Self { - in_spans: spans.into_iter().collect(), - ..self - } - } - - pub fn scope_mut(&mut self) -> &mut [span::MockSpan] { - &mut self.in_spans[..] - } } -impl fmt::Display for MockEvent { +impl fmt::Display for ExpectedEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "an event{}", self.metadata) } } -impl fmt::Debug for MockEvent { +impl fmt::Debug for ExpectedEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut s = f.debug_struct("MockEvent"); @@ -159,8 +619,8 @@ impl fmt::Debug for MockEvent { s.field("parent", &format_args!("{:?}", parent)); } - if !self.in_spans.is_empty() { - s.field("in_spans", &self.in_spans); + if let Some(in_spans) = &self.in_spans { + s.field("in_spans", in_spans); } s.finish() diff --git a/tracing-mock/src/expect.rs b/tracing-mock/src/expect.rs new file mode 100644 index 0000000000..044f134580 --- /dev/null +++ b/tracing-mock/src/expect.rs @@ -0,0 +1,93 @@ +use std::fmt; + +use crate::{ + event::ExpectedEvent, + field::{ExpectedField, ExpectedFields, ExpectedValue}, + span::{ExpectedSpan, NewSpan}, +}; + +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum Expect { + Event(ExpectedEvent), + FollowsFrom { + consequence: ExpectedSpan, + cause: ExpectedSpan, + }, + Enter(ExpectedSpan), + Exit(ExpectedSpan), + CloneSpan(ExpectedSpan), + DropSpan(ExpectedSpan), + Visit(ExpectedSpan, ExpectedFields), + NewSpan(NewSpan), + Nothing, +} + +pub fn event() -> ExpectedEvent { + ExpectedEvent { + ..Default::default() + } +} + +pub fn field(name: K) -> ExpectedField +where + String: From, +{ + ExpectedField { + name: name.into(), + value: ExpectedValue::Any, + } +} + +pub fn span() -> ExpectedSpan { + ExpectedSpan { + ..Default::default() + } +} + +impl Expect { + pub(crate) fn bad(&self, name: impl AsRef, what: fmt::Arguments<'_>) { + let name = name.as_ref(); + match self { + Expect::Event(e) => panic!( + "\n[{}] expected event {}\n[{}] but instead {}", + name, e, name, what, + ), + Expect::FollowsFrom { consequence, cause } => panic!( + "\n[{}] expected consequence {} to follow cause {} but instead {}", + name, consequence, cause, what, + ), + Expect::Enter(e) => panic!( + "\n[{}] expected to enter {}\n[{}] but instead {}", + name, e, name, what, + ), + Expect::Exit(e) => panic!( + "\n[{}] expected to exit {}\n[{}] but instead {}", + name, e, name, what, + ), + Expect::CloneSpan(e) => { + panic!( + "\n[{}] expected to clone {}\n[{}] but instead {}", + name, e, name, what, + ) + } + Expect::DropSpan(e) => { + panic!( + "\n[{}] expected to drop {}\n[{}] but instead {}", + name, e, name, what, + ) + } + Expect::Visit(e, fields) => panic!( + "\n[{}] expected {} to record {}\n[{}] but instead {}", + name, e, fields, name, what, + ), + Expect::NewSpan(e) => panic!( + "\n[{}] expected {}\n[{}] but instead {}", + name, e, name, what + ), + Expect::Nothing => panic!( + "\n[{}] expected nothing else to happen\n[{}] but {} instead", + name, name, what, + ), + } + } +} diff --git a/tracing-mock/src/expectation.rs b/tracing-mock/src/expectation.rs deleted file mode 100644 index 0328754fc8..0000000000 --- a/tracing-mock/src/expectation.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::{ - event::MockEvent, - field, - span::{MockSpan, NewSpan}, -}; - -#[derive(Debug, Eq, PartialEq)] -pub(crate) enum Expect { - Event(MockEvent), - FollowsFrom { - consequence: MockSpan, - cause: MockSpan, - }, - Enter(MockSpan), - Exit(MockSpan), - CloneSpan(MockSpan), - DropSpan(MockSpan), - Visit(MockSpan, field::Expect), - NewSpan(NewSpan), - Nothing, -} diff --git a/tracing-mock/src/field.rs b/tracing-mock/src/field.rs index bdf22aba1d..ea5f7a4eb7 100644 --- a/tracing-mock/src/field.rs +++ b/tracing-mock/src/field.rs @@ -8,19 +8,19 @@ use tracing::{ use std::{collections::HashMap, fmt}; #[derive(Default, Debug, Eq, PartialEq)] -pub struct Expect { - fields: HashMap, +pub struct ExpectedFields { + fields: HashMap, only: bool, } #[derive(Debug)] -pub struct MockField { - name: String, - value: MockValue, +pub struct ExpectedField { + pub(super) name: String, + pub(super) value: ExpectedValue, } #[derive(Debug)] -pub enum MockValue { +pub enum ExpectedValue { F64(f64), I64(i64), U64(u64), @@ -30,11 +30,11 @@ pub enum MockValue { Any, } -impl Eq for MockValue {} +impl Eq for ExpectedValue {} -impl PartialEq for MockValue { +impl PartialEq for ExpectedValue { fn eq(&self, other: &Self) -> bool { - use MockValue::*; + use ExpectedValue::*; match (self, other) { (F64(a), F64(b)) => { @@ -55,34 +55,24 @@ impl PartialEq for MockValue { } } -pub fn mock(name: K) -> MockField -where - String: From, -{ - MockField { - name: name.into(), - value: MockValue::Any, - } -} - -pub fn msg(message: impl fmt::Display) -> MockField { - MockField { +pub fn msg(message: impl fmt::Display) -> ExpectedField { + ExpectedField { name: "message".to_string(), - value: MockValue::Debug(message.to_string()), + value: ExpectedValue::Debug(message.to_string()), } } -impl MockField { +impl ExpectedField { /// Expect a field with the given name and value. pub fn with_value(self, value: &dyn Value) -> Self { Self { - value: MockValue::from(value), + value: ExpectedValue::from(value), ..self } } - pub fn and(self, other: MockField) -> Expect { - Expect { + pub fn and(self, other: ExpectedField) -> ExpectedFields { + ExpectedFields { fields: HashMap::new(), only: false, } @@ -90,8 +80,8 @@ impl MockField { .and(other) } - pub fn only(self) -> Expect { - Expect { + pub fn only(self) -> ExpectedFields { + ExpectedFields { fields: HashMap::new(), only: true, } @@ -99,9 +89,9 @@ impl MockField { } } -impl From for Expect { - fn from(field: MockField) -> Self { - Expect { +impl From for ExpectedFields { + fn from(field: ExpectedField) -> Self { + ExpectedFields { fields: HashMap::new(), only: false, } @@ -109,8 +99,8 @@ impl From for Expect { } } -impl Expect { - pub fn and(mut self, field: MockField) -> Self { +impl ExpectedFields { + pub fn and(mut self, field: ExpectedField) -> Self { self.fields.insert(field.name, field.value); self } @@ -129,7 +119,7 @@ impl Expect { ) { let value = value.into(); match self.fields.remove(name) { - Some(MockValue::Any) => {} + Some(ExpectedValue::Any) => {} Some(expected) => assert!( expected == value, "\n[{}] expected `{}` to contain:\n\t`{}{}`\nbut got:\n\t`{}{}`", @@ -161,22 +151,22 @@ impl Expect { } } -impl fmt::Display for MockValue { +impl fmt::Display for ExpectedValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MockValue::F64(v) => write!(f, "f64 = {:?}", v), - MockValue::I64(v) => write!(f, "i64 = {:?}", v), - MockValue::U64(v) => write!(f, "u64 = {:?}", v), - MockValue::Bool(v) => write!(f, "bool = {:?}", v), - MockValue::Str(v) => write!(f, "&str = {:?}", v), - MockValue::Debug(v) => write!(f, "&fmt::Debug = {:?}", v), - MockValue::Any => write!(f, "_ = _"), + ExpectedValue::F64(v) => write!(f, "f64 = {:?}", v), + ExpectedValue::I64(v) => write!(f, "i64 = {:?}", v), + ExpectedValue::U64(v) => write!(f, "u64 = {:?}", v), + ExpectedValue::Bool(v) => write!(f, "bool = {:?}", v), + ExpectedValue::Str(v) => write!(f, "&str = {:?}", v), + ExpectedValue::Debug(v) => write!(f, "&fmt::Debug = {:?}", v), + ExpectedValue::Any => write!(f, "_ = _"), } } } pub struct CheckVisitor<'a> { - expect: &'a mut Expect, + expect: &'a mut ExpectedFields, ctx: &'a str, subscriber_name: &'a str, } @@ -229,35 +219,35 @@ impl<'a> CheckVisitor<'a> { } } -impl<'a> From<&'a dyn Value> for MockValue { +impl<'a> From<&'a dyn Value> for ExpectedValue { fn from(value: &'a dyn Value) -> Self { struct MockValueBuilder { - value: Option, + value: Option, } impl Visit for MockValueBuilder { fn record_f64(&mut self, _: &Field, value: f64) { - self.value = Some(MockValue::F64(value)); + self.value = Some(ExpectedValue::F64(value)); } fn record_i64(&mut self, _: &Field, value: i64) { - self.value = Some(MockValue::I64(value)); + self.value = Some(ExpectedValue::I64(value)); } fn record_u64(&mut self, _: &Field, value: u64) { - self.value = Some(MockValue::U64(value)); + self.value = Some(ExpectedValue::U64(value)); } fn record_bool(&mut self, _: &Field, value: bool) { - self.value = Some(MockValue::Bool(value)); + self.value = Some(ExpectedValue::Bool(value)); } fn record_str(&mut self, _: &Field, value: &str) { - self.value = Some(MockValue::Str(value.to_owned())); + self.value = Some(ExpectedValue::Str(value.to_owned())); } fn record_debug(&mut self, _: &Field, value: &dyn fmt::Debug) { - self.value = Some(MockValue::Debug(format!("{:?}", value))); + self.value = Some(ExpectedValue::Debug(format!("{:?}", value))); } } @@ -274,7 +264,7 @@ impl<'a> From<&'a dyn Value> for MockValue { } } -impl fmt::Display for Expect { +impl fmt::Display for ExpectedFields { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "fields ")?; let entries = self diff --git a/tracing-mock/src/layer.rs b/tracing-mock/src/layer.rs index 0a0a02005d..ab48171b9d 100644 --- a/tracing-mock/src/layer.rs +++ b/tracing-mock/src/layer.rs @@ -1,7 +1,124 @@ +//! An implementation of the [`Layer`] trait which validates that +//! the `tracing` data it recieves matches the expected output for a test. +//! +//! +//! The [`MockLayer`] is the central component in these tools. The +//! `MockLayer` has expectations set on it which are later +//! validated as the code under test is run. +//! +//! ``` +//! use tracing_mock::{expect, field, layer}; +//! use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +//! +//! let (layer, handle) = layer::mock() +//! // Expect a single event with a specified message +//! .event(expect::event().with_fields(field::msg("droids"))) +//! .run_with_handle(); +//! +//! // Use `set_default` to apply the `MockSubscriber` until the end +//! // of the current scope (when the guard `_subscriber` is dropped). +//! let _subscriber = tracing_subscriber::registry() +//! .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) +//! .set_default(); +//! +//! // These *are* the droids we are looking for +//! tracing::info!("droids"); +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! A more complex example may consider multiple spans and events with +//! their respective fields: +//! +//! ``` +//! use tracing_mock::{expect, field, layer}; +//! use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +//! +//! let span = expect::span() +//! .named("my_span"); +//! let (layer, handle) = layer::mock() +//! // Enter a matching span +//! .enter(span.clone()) +//! // Record an event with message "collect parting message" +//! .event(expect::event().with_fields(field::msg("say hello"))) +//! // Exit a matching span +//! .exit(span) +//! // Expect no further messages to be recorded +//! .only() +//! // Return the layer and handle +//! .run_with_handle(); +//! +//! // Use `set_default` to apply the `MockLayers` until the end +//! // of the current scope (when the guard `_subscriber` is dropped). +//! let _subscriber = tracing_subscriber::registry() +//! .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) +//! .set_default(); +//! +//! { +//! let span = tracing::trace_span!( +//! "my_span", +//! greeting = "hello world", +//! ); +//! +//! let _guard = span.enter(); +//! tracing::info!("say hello"); +//! } +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! If we modify the previous example so that we **don't** enter the +//! span before recording an event, the test will fail: +//! +//! ```should_panic +//! use tracing_mock::{expect, field, layer}; +//! use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +//! +//! let span = expect::span() +//! .named("my_span"); +//! let (layer, handle) = layer::mock() +//! // Enter a matching span +//! .enter(span.clone()) +//! // Record an event with message "collect parting message" +//! .event(expect::event().with_fields(field::msg("say hello"))) +//! // Exit a matching span +//! .exit(span) +//! // Expect no further messages to be recorded +//! .only() +//! // Return the subscriber and handle +//! .run_with_handle(); +//! +//! // Use `set_default` to apply the `MockSubscriber` until the end +//! // of the current scope (when the guard `_subscriber` is dropped). +//! let _subscriber = tracing_subscriber::registry() +//! .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) +//! .set_default(); +//! +//! { +//! let span = tracing::trace_span!( +//! "my_span", +//! greeting = "hello world", +//! ); +//! +//! // Don't enter the span. +//! // let _guard = span.enter(); +//! tracing::info!("say hello"); +//! } +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! [`Layer`]: trait@tracing_subscriber::layer::Layer use crate::{ - event::MockEvent, - expectation::Expect, - span::{MockSpan, NewSpan}, + event::ExpectedEvent, + expect::Expect, + span::{ExpectedSpan, NewSpan}, subscriber::MockHandle, }; use tracing_core::{ @@ -19,6 +136,54 @@ use std::{ sync::{Arc, Mutex}, }; +/// Create a [`MockLayerBuilder`] used to construct a +/// [`MockLayer`]. +/// +/// For additional information and examples, see the [`layer`] +/// module and [`MockLayerBuilder`] documentation. +/// +/// # Examples +/// +/// ``` +/// use tracing_mock::{expect, field, layer}; +/// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +/// +/// let span = expect::span() +/// .named("my_span"); +/// let (layer, handle) = layer::mock() +/// // Enter a matching span +/// .enter(span.clone()) +/// // Record an event with message "collect parting message" +/// .event(expect::event().with_fields(field::msg("say hello"))) +/// // Exit a matching span +/// .exit(span) +/// // Expect no further messages to be recorded +/// .only() +/// // Return the subscriber and handle +/// .run_with_handle(); +/// +/// // Use `set_default` to apply the `MockSubscriber` until the end +/// // of the current scope (when the guard `_subscriber` is dropped). +/// let _subscriber = tracing_subscriber::registry() +/// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) +/// .set_default(); +/// +/// { +/// let span = tracing::trace_span!( +/// "my_span", +/// greeting = "hello world", +/// ); +/// +/// let _guard = span.enter(); +/// tracing::info!("say hello"); +/// } +/// +/// // Use the handle to check the assertions. This line will panic if an +/// // assertion is not met. +/// handle.assert_finished(); +/// ``` +/// +/// [`layer`]: mod@crate::layer #[must_use] pub fn mock() -> MockLayerBuilder { MockLayerBuilder { @@ -30,16 +195,81 @@ pub fn mock() -> MockLayerBuilder { } } +/// Create a [`MockLayerBuilder`] with a name already set. +/// +/// This constructor is equivalent to calling +/// [`MockLayerBuilder::named`] in the following way" +/// `layer::mock().named(name)`. +/// +/// For additional information and examples, see the [`layer`] +/// module and [`MockLayerBuilder`] documentation. +/// +/// # Examples +/// +/// The example from [`named`] could be rewritten as: +/// +/// ```should_panic +/// use tracing_mock::{expect, layer}; +/// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +/// +/// let (layer_1, handle_1) = layer::named("subscriber-1") +/// .event(expect::event()) +/// .run_with_handle(); +/// +/// let (layer_2, handle_2) = layer::named("subscriber-2") +/// .event(expect::event()) +/// .run_with_handle(); +/// +/// let _subscriber = tracing_subscriber::registry() +/// .with( +/// layer_2.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true)) +/// ) +/// .set_default(); +/// { +/// let _subscriber = tracing_subscriber::registry() +/// .with( +/// layer_1 +/// .with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true)) +/// ) +/// .set_default(); +/// +/// tracing::info!("a"); +/// } +/// +/// handle_1.assert_finished(); +/// handle_2.assert_finished(); +/// ``` +/// +/// [`MockLayerBuilder::named`]: fn@crate::layer::MockLayerBuilder::named +/// [`layer`]: mod@crate::layer #[must_use] pub fn named(name: impl std::fmt::Display) -> MockLayerBuilder { mock().named(name) } +/// A builder for constructing [`MockLayer`]s. +/// +/// The methods on this builder set expectations which are then +/// validated by the constructed [`MockLayer`]. +/// +/// For a detailed description and examples see the documentation +/// for the methods and the [`layer`] module. +/// +/// [`layer`]: mod@crate::layer + pub struct MockLayerBuilder { expected: VecDeque, name: String, } +/// A layer which validates the traces it receives. +/// +/// A `MockLayer` is constructed with a +/// [`MockLayerBuilder`]. For a detailed description and examples, +/// see the documentation for that struct and for the [`layer`] +/// module. +/// +/// [`layer`]: mod@crate::layer pub struct MockLayer { expected: Arc>>, current: Mutex>, @@ -47,6 +277,72 @@ pub struct MockLayer { } impl MockLayerBuilder { + /// Overrides the name printed by the mock layer's debugging output. + /// + /// The debugging output is displayed if the test panics, or if the test is + /// run with `--nocapture`. + /// + /// By default, the mock layer's name is the name of the test + /// (*technically*, the name of the thread where it was created, which is + /// the name of the test unless tests are run with `--test-threads=1`). + /// When a test has only one mock layer, this is sufficient. However, + /// some tests may include multiple layers, in order to test + /// interactions between multiple layers. In that case, it can be + /// helpful to give each layers a separate name to distinguish where the + /// debugging output comes from. + /// + /// # Examples + /// + /// In the following example, we create two layers, both + /// expecting to receive an event. As we only record a single + /// event, the test will fail: + /// + /// ```should_panic + /// use tracing_mock::{layer, expect}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer_1, handle_1) = layer::mock() + /// .named("layer-1") + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let (layer_2, handle_2) = layer::mock() + /// .named("layer-2") + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with( + /// layer_2.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true)) + /// ) + /// .set_default(); + /// { + /// let _subscriber = tracing_subscriber::registry() + /// .with( + /// layer_1 + /// .with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true)) + /// ) + /// .set_default(); + /// + /// tracing::info!("a"); + /// } + /// + /// handle_1.assert_finished(); + /// handle_2.assert_finished(); + /// ``` + /// + /// In the test output, we see that the layer which didn't + /// received the event was the one named `layer-2`, which is + /// correct as the layer named `layer-1` was the default + /// when the event was recorded: + /// + /// ```text + /// [main::layer-2] more notifications expected: [ + /// Event( + /// MockEvent, + /// ), + /// ]', tracing-mock/src/subscriber.rs:472:13 + /// ``` pub fn named(mut self, name: impl fmt::Display) -> Self { use std::fmt::Write; if !self.name.is_empty() { @@ -57,11 +353,125 @@ impl MockLayerBuilder { self } - pub fn event(mut self, event: MockEvent) -> Self { + /// Adds an expectation that an event matching the [`ExpectedEvent`] + /// will be recorded next. + /// + /// The `event` can be a default mock which will match any event + /// (`expect::event()`) or can include additional expectations. + /// See the [`ExpectedEvent`] documentation for more details. + /// + /// If an event is recorded that doesn't match the `ExpectedEvent`, + /// or if something else (such as entering a span) is recorded + /// first, then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer, handle) = layer::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// tracing::info!("event"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// A span is entered before the event, causing the test to fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer, handle) = layer::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// let span = tracing::info_span!("span"); + /// let _guard = span.enter(); + /// tracing::info!("event"); + /// + /// handle.assert_finished(); + /// ``` + pub fn event(mut self, event: ExpectedEvent) -> Self { self.expected.push_back(Expect::Event(event)); self } + /// Adds an expectation that the creation of a span will be + /// recorded next. + /// + /// This function accepts `Into` instead of + /// [`ExpectedSpan`] directly. [`NewSpan`] can be used to test + /// span fields and the span parent. + /// + /// The new span doesn't need to be entered for this expectation + /// to succeed. + /// + /// If a span is recorded that doesn't match the `ExpectedSpan`, + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing") + /// .with_field(expect::field("testing").with_value(&"yes")); + /// let (layer, handle) = layer::mock() + /// .new_span(span) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// _ = tracing::info_span!("the span we're testing", testing = "yes"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is created, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing") + /// .with_field(expect::field("testing").with_value(&"yes")); + /// let (layer, handle) = layer::mock() + /// .new_span(span) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// tracing::info!("an event"); + /// _ = tracing::info_span!("the span we're testing", testing = "yes"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`ExpectedSpan`]: struct@crate::span::ExpectedSpan + /// [`NewSpan`]: struct@crate::span::NewSpan pub fn new_span(mut self, new_span: I) -> Self where I: Into, @@ -70,21 +480,252 @@ impl MockLayerBuilder { self } - pub fn enter(mut self, span: MockSpan) -> Self { + /// Adds an expectation that entering a span matching the + /// [`ExpectedSpan`] will be recorded next. + /// + /// This expectation is generally accompanied by a call to + /// [`exit`], since an entered span will typically be exited. If used + /// together with [`only`], this is likely necessary, because the span + /// will be dropped before the test completes (except in rare cases, + /// such as if [`std::mem::forget`] is used). + /// + /// If the span that is entered doesn't match the [`ExpectedSpan`], + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (layer, handle) = layer::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// } + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is entered, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (layer, handle) = layer::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// { + /// tracing::info!("an event"); + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// } + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`exit`]: fn@Self::exit + /// [`only`]: fn@Self::only + pub fn enter(mut self, span: ExpectedSpan) -> Self { self.expected.push_back(Expect::Enter(span)); self } - pub fn exit(mut self, span: MockSpan) -> Self { + /// Adds an expectation that exiting a span matching the + /// [`ExpectedSpan`] will be recorded next. + /// + /// As a span may be entered and exited multiple times, + /// this is different from the span being closed. In + /// general [`enter`] and `exit` should be paired. + /// + /// If the span that is exited doesn't match the [`ExpectedSpan`], + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// **Note**: Ensure that the guard returned by [`Span::enter`] + /// is dropped before calling [`MockHandle::assert_finished`]. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (layer, handle) = layer::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// } + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is exited, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (layer, handle) = layer::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// tracing::info!("an event"); + /// } + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`enter`]: fn@Self::enter + /// [`MockHandle::assert_finished`]: fn@crate::subscriber::MockHandle::assert_finished + /// [`Span::enter`]: fn@tracing::Span::enter + pub fn exit(mut self, span: ExpectedSpan) -> Self { self.expected.push_back(Expect::Exit(span)); self } - pub fn done(mut self) -> Self { + /// Expects that no further traces are received. + /// + /// The call to `only` should appear immediately before the final + /// call to [`run`] or [`run_with_handle`], as any expectations which + /// are added after `only` will not be considered. + /// + /// # Examples + /// + /// Consider this simple test. It passes even though we only + /// expect a single event, but receive three: + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer, handle) = layer::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// tracing::info!("a"); + /// tracing::info!("b"); + /// tracing::info!("c"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// After including `only`, the test will fail: + /// + /// ```should_panic + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer, handle) = layer::mock() + /// .event(expect::event()) + /// .only() + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// tracing::info!("a"); + /// tracing::info!("b"); + /// tracing::info!("c"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`run`]: fn@Self::run + /// [`run_with_handle`]: fn@Self::run_with_handle + pub fn only(mut self) -> Self { self.expected.push_back(Expect::Nothing); self } + /// Consume this builder and return a [`MockLayer`] which can + /// be set as the default subscriber. + /// + /// This function is similar to [`run_with_handle`], but it doesn't + /// return a [`MockHandle`]. This is useful if the desired + /// assertions can be checked externally to the subscriber. + /// + /// # Examples + /// + /// The following test is used within the `tracing-subscriber` + /// codebase: + /// + /// ``` + /// use tracing::Subscriber; + /// use tracing_mock::layer; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let unfiltered = layer::named("unfiltered").run().boxed(); + /// let info = layer::named("info") + /// .run() + /// .with_filter(tracing_core::LevelFilter::INFO) + /// .boxed(); + /// let debug = layer::named("debug") + /// .run() + /// .with_filter(tracing_core::LevelFilter::DEBUG) + /// .boxed(); + /// + /// let subscriber = tracing_subscriber::registry().with(vec![unfiltered, info, debug]); + /// + /// assert_eq!(subscriber.max_level_hint(), None); + /// ``` + /// + /// [`MockHandle`]: struct@crate::subscriber::MockHandle + /// [`run_with_handle`]: fn@Self::run_with_handle pub fn run(self) -> MockLayer { MockLayer { expected: Arc::new(Mutex::new(self.expected)), @@ -93,6 +734,31 @@ impl MockLayerBuilder { } } + /// Consume this builder and return a [`MockLayer`] which can + /// be set as the default subscriber and a [`MockHandle`] which can + /// be used to validate the provided expectations. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{expect, layer}; + /// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; + /// + /// let (layer, handle) = layer::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _subscriber = tracing_subscriber::registry() + /// .with(layer.with_filter(tracing_subscriber::filter::filter_fn(move |_meta| true))) + /// .set_default(); + /// + /// tracing::info!("event"); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`MockHandle`]: struct@crate::subscriber::MockHandle + /// [`MockLayer`]: struct@crate::layer::MockLayer pub fn run_with_handle(self) -> (MockLayer, MockHandle) { let expected = Arc::new(Mutex::new(self.expected)); let handle = MockHandle::new(expected.clone(), self.name.clone()); @@ -108,7 +774,7 @@ impl MockLayerBuilder { impl MockLayer { fn check_span_ref<'spans, S>( &self, - expected: &MockSpan, + expected: &ExpectedSpan, actual: &SpanRef<'spans, S>, what_happened: impl fmt::Display, ) where @@ -164,6 +830,46 @@ impl MockLayer { ); } } + + fn check_event_scope( + &self, + current_scope: Option>, + expected_scope: &mut [ExpectedSpan], + ) where + C: for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>, + { + let mut current_scope = current_scope.into_iter().flatten(); + let mut i = 0; + for (expected, actual) in expected_scope.iter_mut().zip(&mut current_scope) { + println!( + "[{}] event_scope[{}] actual={} ({:?}); expected={}", + self.name, + i, + actual.name(), + actual.id(), + expected + ); + self.check_span_ref( + expected, + &actual, + format_args!("the {}th span in the event's scope to be", i), + ); + i += 1; + } + let remaining_expected = &expected_scope[i..]; + assert!( + remaining_expected.is_empty(), + "\n[{}] did not observe all expected spans in event scope!\n[{}] missing: {:#?}", + self.name, + self.name, + remaining_expected, + ); + assert!( + current_scope.next().is_none(), + "\n[{}] did not expect all spans in the actual event scope!", + self.name, + ); + } } impl Layer for MockLayer @@ -200,38 +906,10 @@ where Some(Expect::Event(mut expected)) => { let get_parent_name = || cx.event_span(event).map(|span| span.name().to_string()); expected.check(event, get_parent_name, &self.name); - let mut current_scope = cx.event_scope(event).into_iter().flatten(); - let expected_scope = expected.scope_mut(); - let mut i = 0; - for (expected, actual) in expected_scope.iter_mut().zip(&mut current_scope) { - println!( - "[{}] event_scope[{}] actual={} ({:?}); expected={}", - self.name, - i, - actual.name(), - actual.id(), - expected - ); - self.check_span_ref( - expected, - &actual, - format_args!("the {}th span in the event's scope to be", i), - ); - i += 1; + + if let Some(expected_scope) = expected.scope_mut() { + self.check_event_scope(cx.event_scope(event), expected_scope); } - let remaining_expected = &expected_scope[i..]; - assert!( - remaining_expected.is_empty(), - "\n[{}] did not observe all expected spans in event scope!\n[{}] missing: {:#?}", - self.name, - self.name, - remaining_expected, - ); - assert!( - current_scope.next().is_none(), - "\n[{}] did not expect all spans in the actual event scope!", - self.name, - ); } Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)), } @@ -366,7 +1044,7 @@ where impl fmt::Debug for MockLayer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut s = f.debug_struct("MockLayer"); + let mut s = f.debug_struct("ExpectSubscriber"); s.field("name", &self.name); if let Ok(expected) = self.expected.try_lock() { diff --git a/tracing-mock/src/lib.rs b/tracing-mock/src/lib.rs index a8ba0865b7..720efbe30a 100644 --- a/tracing-mock/src/lib.rs +++ b/tracing-mock/src/lib.rs @@ -1,10 +1,11 @@ +#![doc = include_str!("../README.md")] use std::{ pin::Pin, task::{Context, Poll}, }; pub mod event; -mod expectation; +pub mod expect; pub mod field; mod metadata; pub mod span; @@ -33,25 +34,32 @@ impl Parent { parent_name: Option<&str>, provided_parent: Option, ctx: impl std::fmt::Display, - collector_name: &str, + subscriber_name: &str, ) { match self { Parent::ExplicitRoot => { assert!( provided_parent.is_none(), "[{}] expected {} to be an explicit root, but its parent was actually {:?} (name: {:?})", - collector_name, + subscriber_name, ctx, provided_parent, parent_name, ); } Parent::Explicit(expected_parent) => { + assert!( + provided_parent.is_some(), + "[{}] expected {} to have explicit parent {}, but it has no explicit parent", + subscriber_name, + ctx, + expected_parent, + ); assert_eq!( Some(expected_parent.as_ref()), parent_name, "[{}] expected {} to have explicit parent {}, but its parent was actually {:?} (name: {:?})", - collector_name, + subscriber_name, ctx, expected_parent, provided_parent, @@ -61,8 +69,8 @@ impl Parent { Parent::ContextualRoot => { assert!( provided_parent.is_none(), - "[{}] expected {} to have a contextual parent, but its parent was actually {:?} (name: {:?})", - collector_name, + "[{}] expected {} to be a contextual root, but its parent was actually {:?} (name: {:?})", + subscriber_name, ctx, provided_parent, parent_name, @@ -70,15 +78,15 @@ impl Parent { assert!( parent_name.is_none(), "[{}] expected {} to be contextual a root, but we were inside span {:?}", - collector_name, + subscriber_name, ctx, parent_name, ); } Parent::Contextual(expected_parent) => { assert!(provided_parent.is_none(), - "[{}] expected {} to have a contextual parent\nbut its parent was actually {:?} (name: {:?})", - collector_name, + "[{}] expected {} to have a contextual parent\nbut it has the explicit parent {:?} (name: {:?})", + subscriber_name, ctx, provided_parent, parent_name, @@ -87,7 +95,7 @@ impl Parent { Some(expected_parent.as_ref()), parent_name, "[{}] expected {} to have contextual parent {:?}, but got {:?}", - collector_name, + subscriber_name, ctx, expected_parent, parent_name, diff --git a/tracing-mock/src/metadata.rs b/tracing-mock/src/metadata.rs index 8c4c3a9c89..49347434fe 100644 --- a/tracing-mock/src/metadata.rs +++ b/tracing-mock/src/metadata.rs @@ -2,14 +2,19 @@ use std::fmt; use tracing::Metadata; #[derive(Clone, Debug, Eq, PartialEq, Default)] -pub struct Expect { - pub name: Option, - pub level: Option, - pub target: Option, +pub(crate) struct ExpectedMetadata { + pub(crate) name: Option, + pub(crate) level: Option, + pub(crate) target: Option, } -impl Expect { - pub fn check(&self, actual: &Metadata<'_>, ctx: fmt::Arguments<'_>, subscriber_name: &str) { +impl ExpectedMetadata { + pub(crate) fn check( + &self, + actual: &Metadata<'_>, + ctx: fmt::Arguments<'_>, + subscriber_name: &str, + ) { if let Some(ref expected_name) = self.name { let name = actual.name(); assert!( @@ -48,7 +53,7 @@ impl Expect { } } -impl fmt::Display for Expect { +impl fmt::Display for ExpectedMetadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(ref name) = self.name { write!(f, " named `{}`", name)?; diff --git a/tracing-mock/src/span.rs b/tracing-mock/src/span.rs index a55aaabc93..9af084fe69 100644 --- a/tracing-mock/src/span.rs +++ b/tracing-mock/src/span.rs @@ -1,5 +1,5 @@ #![allow(missing_docs)] -use super::{field, metadata, Parent}; +use super::{expect, field::ExpectedFields, metadata::ExpectedMetadata, Parent}; use std::fmt; /// A mock span. @@ -7,37 +7,31 @@ use std::fmt; /// This is intended for use with the mock subscriber API in the /// `subscriber` module. #[derive(Clone, Default, Eq, PartialEq)] -pub struct MockSpan { - pub(crate) metadata: metadata::Expect, +pub struct ExpectedSpan { + pub(crate) metadata: ExpectedMetadata, } #[derive(Default, Eq, PartialEq)] pub struct NewSpan { - pub(crate) span: MockSpan, - pub(crate) fields: field::Expect, + pub(crate) span: ExpectedSpan, + pub(crate) fields: ExpectedFields, pub(crate) parent: Option, } -pub fn mock() -> MockSpan { - MockSpan { - ..Default::default() - } -} - -pub fn named(name: I) -> MockSpan +pub fn named(name: I) -> ExpectedSpan where I: Into, { - mock().named(name) + expect::span().named(name) } -impl MockSpan { +impl ExpectedSpan { pub fn named(self, name: I) -> Self where I: Into, { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { name: Some(name.into()), ..self.metadata }, @@ -46,7 +40,7 @@ impl MockSpan { pub fn at_level(self, level: tracing::Level) -> Self { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { level: Some(level), ..self.metadata }, @@ -58,7 +52,7 @@ impl MockSpan { I: Into, { Self { - metadata: metadata::Expect { + metadata: ExpectedMetadata { target: Some(target.into()), ..self.metadata }, @@ -103,7 +97,7 @@ impl MockSpan { pub fn with_field(self, fields: I) -> NewSpan where - I: Into, + I: Into, { NewSpan { span: self, @@ -113,7 +107,7 @@ impl MockSpan { } } -impl fmt::Debug for MockSpan { +impl fmt::Debug for ExpectedSpan { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut s = f.debug_struct("MockSpan"); @@ -133,7 +127,7 @@ impl fmt::Debug for MockSpan { } } -impl fmt::Display for MockSpan { +impl fmt::Display for ExpectedSpan { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.metadata.name.is_some() { write!(f, "a span{}", self.metadata) @@ -143,8 +137,8 @@ impl fmt::Display for MockSpan { } } -impl From for NewSpan { - fn from(span: MockSpan) -> Self { +impl From for NewSpan { + fn from(span: ExpectedSpan) -> Self { Self { span, ..Default::default() @@ -177,7 +171,7 @@ impl NewSpan { pub fn with_field(self, fields: I) -> NewSpan where - I: Into, + I: Into, { NewSpan { fields: fields.into(), diff --git a/tracing-mock/src/subscriber.rs b/tracing-mock/src/subscriber.rs index 9a73da28c2..ef7a93b148 100644 --- a/tracing-mock/src/subscriber.rs +++ b/tracing-mock/src/subscriber.rs @@ -1,13 +1,150 @@ -#![allow(missing_docs)] -use super::{ - event::MockEvent, - expectation::Expect, - field as mock_field, - span::{MockSpan, NewSpan}, +//! An implementation of the [`Subscriber`] trait to receive and validate +//! `tracing` data. +//! +//! The [`MockSubscriber`] is the central component of this crate. The +//! `MockSubscriber` has expectations set on it which are later +//! validated as the code under test is run. +//! +//! # Examples +//! +//! ``` +//! use tracing_mock::{subscriber, expect, field}; +//! +//! let (subscriber, handle) = subscriber::mock() +//! // Expect a single event with a specified message +//! .event(expect::event().with_fields(field::msg("droids"))) +//! .only() +//! .run_with_handle(); +//! +//! // Use `with_default` to apply the `MockSubscriber` for the duration +//! // of the closure - this is what we are testing. +//! tracing::subscriber::with_default(subscriber, || { +//! // These *are* the droids we are looking for +//! tracing::info!("droids"); +//! }); +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! A more complex example may consider multiple spans and events with +//! their respective fields: +//! +//! ``` +//! use tracing_mock::{subscriber, expect, field}; +//! +//! let span = expect::span() +//! .named("my_span"); +//! let (subscriber, handle) = subscriber::mock() +//! // Enter a matching span +//! .enter(span.clone()) +//! // Record an event with message "collect parting message" +//! .event(expect::event().with_fields(field::msg("collect parting message"))) +//! // Record a value for the field `parting` on a matching span +//! .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +//! // Exit a matching span +//! .exit(span) +//! // Expect no further messages to be recorded +//! .only() +//! // Return the subscriber and handle +//! .run_with_handle(); +//! +//! // Use `with_default` to apply the `MockSubscriber` for the duration +//! // of the closure - this is what we are testing. +//! tracing::subscriber::with_default(subscriber, || { +//! let span = tracing::trace_span!( +//! "my_span", +//! greeting = "hello world", +//! parting = tracing::field::Empty +//! ); +//! +//! let _guard = span.enter(); +//! tracing::info!("collect parting message"); +//! let parting = "goodbye world!"; +//! +//! span.record("parting", &parting); +//! }); +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! If we modify the previous example so that we **don't** enter the +//! span before recording an event, the test will fail: +//! +//! ```should_panic +//! use tracing_mock::{subscriber, expect, field}; +//! +//! let span = expect::span() +//! .named("my_span"); +//! let (subscriber, handle) = subscriber::mock() +//! .enter(span.clone()) +//! .event(expect::event().with_fields(field::msg("collect parting message"))) +//! .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +//! .exit(span) +//! .only() +//! .run_with_handle(); +//! +//! // Use `with_default` to apply the `MockSubscriber` for the duration +//! // of the closure - this is what we are testing. +//! tracing::subscriber::with_default(subscriber, || { +//! let span = tracing::trace_span!( +//! "my_span", +//! greeting = "hello world", +//! parting = tracing::field::Empty +//! ); +//! +//! // Don't enter the span. +//! // let _guard = span.enter(); +//! tracing::info!("collect parting message"); +//! let parting = "goodbye world!"; +//! +//! span.record("parting", &parting); +//! }); +//! +//! // Use the handle to check the assertions. This line will panic if an +//! // assertion is not met. +//! handle.assert_finished(); +//! ``` +//! +//! This will result in an error message such as the following: +//! +//! ```text +//! thread 'main' panicked at ' +//! [main] expected to enter a span named `my_span` +//! [main] but instead observed event Event { +//! fields: ValueSet { +//! message: collect parting message, +//! callsite: Identifier(0x10eda3278), +//! }, +//! metadata: Metadata { +//! name: "event src/subscriber.rs:27", +//! target: "rust_out", +//! level: Level( +//! Info, +//! ), +//! module_path: "rust_out", +//! location: src/subscriber.rs:27, +//! fields: {message}, +//! callsite: Identifier(0x10eda3278), +//! kind: Kind(EVENT), +//! }, +//! parent: Current, +//! }', tracing/tracing-mock/src/expect.rs:59:33 +//! ``` +//! +//! [`Subscriber`]: trait@tracing::Subscriber +//! [`MockSubscriber`]: struct@crate::subscriber::MockSubscriber +use crate::{ + event::ExpectedEvent, + expect::Expect, + field::ExpectedFields, + span::{ExpectedSpan, NewSpan}, }; use std::{ collections::{HashMap, VecDeque}, - fmt, sync::{ atomic::{AtomicUsize, Ordering}, Arc, Mutex, @@ -37,6 +174,12 @@ struct Running) -> bool> { name: String, } +/// A subscriber which can validate received traces. +/// +/// For a detailed description and examples see the documentation +/// for the methods and the [`subscriber`] module. +/// +/// [`subscriber`]: mod@crate::subscriber pub struct MockSubscriber) -> bool> { expected: VecDeque, max_level: Option, @@ -44,8 +187,67 @@ pub struct MockSubscriber) -> bool> { name: String, } +/// A handle which is used to invoke validation of expectations. +/// +/// The handle is currently only used to assert that all the expected +/// events and spans were seen. +/// +/// For additional information and examples, see the [`subscriber`] +/// module documentation. +/// +/// [`subscriber`]: mod@crate::subscriber pub struct MockHandle(Arc>>, String); +/// Create a new [`MockSubscriber`]. +/// +/// For additional information and examples, see the [`subscriber`] +/// module and [`MockSubscriber`] documentation. +/// +/// # Examples +/// +/// +/// ``` +/// use tracing_mock::{subscriber, expect, field}; +/// +/// let span = expect::span() +/// .named("my_span"); +/// let (subscriber, handle) = subscriber::mock() +/// // Enter a matching span +/// .enter(span.clone()) +/// // Record an event with message "collect parting message" +/// .event(expect::event().with_fields(field::msg("collect parting message"))) +/// // Record a value for the field `parting` on a matching span +/// .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +/// // Exit a matching span +/// .exit(span) +/// // Expect no further messages to be recorded +/// .only() +/// // Return the subscriber and handle +/// .run_with_handle(); +/// +/// // Use `with_default` to apply the `MockSubscriber` for the duration +/// // of the closure - this is what we are testing. +/// tracing::subscriber::with_default(subscriber, || { +/// let span = tracing::trace_span!( +/// "my_span", +/// greeting = "hello world", +/// parting = tracing::field::Empty +/// ); +/// +/// let _guard = span.enter(); +/// tracing::info!("collect parting message"); +/// let parting = "goodbye world!"; +/// +/// span.record("parting", &parting); +/// }); +/// +/// // Use the handle to check the assertions. This line will panic if an +/// // assertion is not met. +/// handle.assert_finished(); +/// ``` +/// +/// [`subscriber`]: mod@crate::subscriber +#[must_use] pub fn mock() -> MockSubscriber) -> bool> { MockSubscriber { expected: VecDeque::new(), @@ -75,6 +277,48 @@ where /// interactions between multiple subscribers. In that case, it can be /// helpful to give each subscriber a separate name to distinguish where the /// debugging output comes from. + /// + /// # Examples + /// + /// In the following example, we create 2 subscribers, both + /// expecting to receive an event. As we only record a single + /// event, the test will fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber_1, handle_1) = subscriber::mock() + /// .named("subscriber-1") + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let (subscriber_2, handle_2) = subscriber::mock() + /// .named("subscriber-2") + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// let _guard = tracing::subscriber::set_default(subscriber_2); + /// + /// tracing::subscriber::with_default(subscriber_1, || { + /// tracing::info!("a"); + /// }); + /// + /// handle_1.assert_finished(); + /// handle_2.assert_finished(); + /// ``` + /// + /// In the test output, we see that the subscriber which didn't + /// received the event was the one named `subscriber-2`, which is + /// correct as the subscriber named `subscriber-1` was the default + /// when the event was recorded: + /// + /// ```text + /// [subscriber-2] more notifications expected: [ + /// Event( + /// MockEvent, + /// ), + /// ]', tracing-mock/src/subscriber.rs:1276:13 + /// ``` pub fn named(self, name: impl ToString) -> Self { Self { name: name.to_string(), @@ -82,59 +326,476 @@ where } } - pub fn enter(mut self, span: MockSpan) -> Self { - self.expected.push_back(Expect::Enter(span)); + /// Adds an expectation that an event matching the [`ExpectedEvent`] + /// will be recorded next. + /// + /// The `event` can be a default mock which will match any event + /// (`expect::event()`) or can include additional expectations. + /// See the [`ExpectedEvent`] documentation for more details. + /// + /// If an event is recorded that doesn't match the `ExpectedEvent`, + /// or if something else (such as entering a span) is recorded + /// first, then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// A span is entered before the event, causing the test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("span"); + /// let _guard = span.enter(); + /// tracing::info!("a"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn event(mut self, event: ExpectedEvent) -> Self { + self.expected.push_back(Expect::Event(event)); self } - pub fn follows_from(mut self, consequence: MockSpan, cause: MockSpan) -> Self { - self.expected - .push_back(Expect::FollowsFrom { consequence, cause }); + /// Adds an expectation that the creation of a span will be + /// recorded next. + /// + /// This function accepts `Into` instead of + /// [`ExpectedSpan`] directly, so it can be used to test + /// span fields and the span parent. This is because a + /// subscriber only receives the span fields and parent when + /// a span is created, not when it is entered. + /// + /// The new span doesn't need to be entered for this expectation + /// to succeed. + /// + /// If a span is recorded that doesn't match the `ExpectedSpan`, + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing") + /// .with_field(expect::field("testing").with_value(&"yes")); + /// let (subscriber, handle) = subscriber::mock() + /// .new_span(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// _ = tracing::info_span!("the span we're testing", testing = "yes"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is created, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing") + /// .with_field(expect::field("testing").with_value(&"yes")); + /// let (subscriber, handle) = subscriber::mock() + /// .new_span(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("an event"); + /// _ = tracing::info_span!("the span we're testing", testing = "yes"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn new_span(mut self, new_span: I) -> Self + where + I: Into, + { + self.expected.push_back(Expect::NewSpan(new_span.into())); self } - pub fn event(mut self, event: MockEvent) -> Self { - self.expected.push_back(Expect::Event(event)); + /// Adds an expectation that entering a span matching the + /// [`ExpectedSpan`] will be recorded next. + /// + /// This expectation is generally accompanied by a call to + /// [`exit`] as well. If used together with [`only`], this + /// is necessary. + /// + /// If the span that is entered doesn't match the [`ExpectedSpan`], + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is entered, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .only() + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("an event"); + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`exit`]: fn@Self::exit + /// [`only`]: fn@Self::only + pub fn enter(mut self, span: ExpectedSpan) -> Self { + self.expected.push_back(Expect::Enter(span)); self } - pub fn exit(mut self, span: MockSpan) -> Self { + /// Adds ab expectation that exiting a span matching the + /// [`ExpectedSpan`] will be recorded next. + /// + /// As a span may be entered and exited multiple times, + /// this is different from the span being closed. In + /// general [`enter`] and `exit` should be paired. + /// + /// If the span that is exited doesn't match the [`ExpectedSpan`], + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is exited, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .enter(span.clone()) + /// .exit(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("the span we're testing"); + /// let _entered = span.enter(); + /// tracing::info!("an event"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`enter`]: fn@Self::enter + pub fn exit(mut self, span: ExpectedSpan) -> Self { self.expected.push_back(Expect::Exit(span)); self } - pub fn clone_span(mut self, span: MockSpan) -> Self { + /// Adds an expectation that cloning a span matching the + /// [`ExpectedSpan`] will be recorded next. + /// + /// The cloned span does need to be entered. + /// + /// If the span that is cloned doesn't match the [`ExpectedSpan`], + /// or if something else (such as an event) is recorded first, + /// then the expectation will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .clone_span(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("the span we're testing"); + /// _ = span.clone(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// An event is recorded before the span is cloned, causing the + /// test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .at_level(tracing::Level::INFO) + /// .named("the span we're testing"); + /// let (subscriber, handle) = subscriber::mock() + /// .clone_span(span) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::info_span!("the span we're testing"); + /// tracing::info!("an event"); + /// _ = span.clone(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn clone_span(mut self, span: ExpectedSpan) -> Self { self.expected.push_back(Expect::CloneSpan(span)); self } + /// **This method is deprecated.** + /// + /// Adds an expectation that a span matching the [`ExpectedSpan`] + /// getting dropped via the deprecated function + /// [`Subscriber::drop_span`] will be recorded next. + /// + /// Instead [`Subscriber::try_close`] should be used on the subscriber + /// and should be asserted with `close_span` (which hasn't been + /// implemented yet, but will be done as part of #539). + /// + /// [`Subscriber::drop_span`]: fn@tracing::Subscriber::drop_span #[allow(deprecated)] - pub fn drop_span(mut self, span: MockSpan) -> Self { + pub fn drop_span(mut self, span: ExpectedSpan) -> Self { self.expected.push_back(Expect::DropSpan(span)); self } - pub fn done(mut self) -> Self { - self.expected.push_back(Expect::Nothing); + /// Adds an expectation that a `follows_from` relationship will be + /// recorded next. Specifically that a span matching `consequence` + /// follows from a span matching `cause`. + /// + /// For further details on what this causal relationship means, see + /// [`Span::follows_from`]. + /// + /// If either of the 2 spans don't match their respective + /// [`ExpectedSpan`] or if something else (such as an event) is + /// recorded first, then the expectation will fail. + /// + /// **Note**: The 2 spans, `consequence` and `cause` are matched + /// by `name` only. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let cause = expect::span().named("cause"); + /// let consequence = expect::span().named("consequence"); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .follows_from(consequence, cause) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let cause = tracing::info_span!("cause"); + /// let consequence = tracing::info_span!("consequence"); + /// + /// consequence.follows_from(&cause); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// The `cause` span doesn't match, it is actually recorded at + /// `Level::WARN` instead of the expected `Level::INFO`, causing + /// this test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let cause = expect::span().named("cause"); + /// let consequence = expect::span().named("consequence"); + /// + /// let (subscriber, handle) = subscriber::mock() + /// .follows_from(consequence, cause) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let cause = tracing::info_span!("another cause"); + /// let consequence = tracing::info_span!("consequence"); + /// + /// consequence.follows_from(&cause); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`Span::follows_from`]: fn@tracing::Span::follows_from + pub fn follows_from(mut self, consequence: ExpectedSpan, cause: ExpectedSpan) -> Self { + self.expected + .push_back(Expect::FollowsFrom { consequence, cause }); self } - pub fn record(mut self, span: MockSpan, fields: I) -> Self + /// Adds an expectation that `fields` are recorded on a span + /// matching the [`ExpectedSpan`] will be recorded next. + /// + /// For further information on how to specify the expected + /// fields, see the documentation on the [`field`] module. + /// + /// If either the span doesn't match the [`ExpectedSpan`], the + /// fields don't match the expected fields, or if something else + /// (such as an event) is recorded first, then the expectation + /// will fail. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .named("my_span"); + /// let (subscriber, handle) = subscriber::mock() + /// .record(span, expect::field("parting").with_value(&"goodbye world!")) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::trace_span!( + /// "my_span", + /// greeting = "hello world", + /// parting = tracing::field::Empty + /// ); + /// span.record("parting", "goodbye world!"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// The value of the recorded field doesn't match the expectation, + /// causing the test to fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let span = expect::span() + /// .named("my_span"); + /// let (subscriber, handle) = subscriber::mock() + /// .record(span, expect::field("parting").with_value(&"goodbye world!")) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// let span = tracing::trace_span!( + /// "my_span", + /// greeting = "hello world", + /// parting = tracing::field::Empty + /// ); + /// span.record("parting", "goodbye universe!"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`field`]: mod@crate::field + pub fn record(mut self, span: ExpectedSpan, fields: I) -> Self where - I: Into, + I: Into, { self.expected.push_back(Expect::Visit(span, fields.into())); self } - pub fn new_span(mut self, new_span: I) -> Self - where - I: Into, - { - self.expected.push_back(Expect::NewSpan(new_span.into())); - self - } - + /// Filter the traces evaluated by the `MockSubscriber`. + /// + /// The filter will be applied to all traces received before + /// any validation occurs - so its position in the call chain + /// is not important. The filter does not perform any validation + /// itself. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .with_filter(|meta| meta.level() <= &tracing::Level::WARN) + /// .event(expect::event()) + /// .only() + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// tracing::warn!("b"); + /// }); + /// + /// handle.assert_finished(); + /// ``` pub fn with_filter(self, filter: G) -> MockSubscriber where G: Fn(&Metadata<'_>) -> bool + 'static, @@ -147,6 +808,39 @@ where } } + /// Sets the max level that will be provided to the `tracing` + /// system. + /// + /// This method can be used to test the internals of `tracing`, + /// but it is also useful to filter out traces on more verbose + /// levels if you only want to verify above a certain level. + /// + /// **Note**: this value determines a global filter, if + /// `with_max_level_hint` is called on multiple subscribers, the + /// global filter will be the least restrictive of all subscribers. + /// To filter the events evaluated by a specific `MockSubscriber`, + /// use [`with_filter`] instead. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .with_max_level_hint(tracing::Level::INFO) + /// .event(expect::event().at_level(tracing::Level::INFO)) + /// .only() + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::debug!("a message we don't care about"); + /// tracing::info!("a message we want to validate"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`with_filter`]: fn@Self::with_filter pub fn with_max_level_hint(self, hint: impl Into) -> Self { Self { max_level: Some(hint.into()), @@ -154,11 +848,108 @@ where } } + /// Expects that no further traces are received. + /// + /// The call to `only` should appear immediately before the final + /// call to `run` or `run_with_handle`, as any expectations which + /// are added after `only` will not be considered. + /// + /// # Examples + /// + /// Consider this simple test. It passes even though we only + /// expect a single event, but receive three: + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// tracing::info!("b"); + /// tracing::info!("c"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// After including `only`, the test will fail: + /// + /// ```should_panic + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .only() + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// tracing::info!("b"); + /// tracing::info!("c"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + pub fn only(mut self) -> Self { + self.expected.push_back(Expect::Nothing); + self + } + + /// Consume the receiver and return an `impl` [`Subscriber`] which can + /// be set as the default subscriber. + /// + /// This function is similar to [`run_with_handle`], but it doesn't + /// return a [`MockHandle`]. This is useful if the desired + /// assertions can be checked externally to the subscriber. + /// + /// # Examples + /// + /// The following test is used within the `tracing` + /// codebase: + /// + /// ``` + /// use tracing_mock::subscriber; + /// + /// tracing::subscriber::with_default(subscriber::mock().run(), || { + /// let foo1 = tracing::span!(tracing::Level::TRACE, "foo"); + /// let foo2 = foo1.clone(); + /// // Two handles that point to the same span are equal. + /// assert_eq!(foo1, foo2); + /// }); + /// ``` + /// + /// [`Subscriber`]: tracing::Subscriber + /// [`run_with_handle`]: fn@Self::run_with_handle pub fn run(self) -> impl Subscriber { let (subscriber, _) = self.run_with_handle(); subscriber } + /// Consume the receiver and return an `impl` [`Subscriber`] which can + /// be set as the default subscriber and a [`MockHandle`] which can + /// be used to validate the provided expectations. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// // subscriber and handle are returned from `run_with_handle()` + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// [`Subscriber`]: tracing::Subscriber pub fn run_with_handle(self) -> (impl Subscriber, MockHandle) { let expected = Arc::new(Mutex::new(self.expected)); let handle = MockHandle(expected.clone(), self.name.clone()); @@ -194,9 +985,7 @@ where Interest::never() } } - fn max_level_hint(&self) -> Option { - println!("[{}] max_level_hint -> {:?}", self.name, self.max_level); self.max_level } @@ -231,6 +1020,14 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Event(mut expected)) => { + #[cfg(feature = "tracing-subscriber")] + { + if expected.scope_mut().is_some() { + unimplemented!( + "Expected scope for events is not supported with `MockSubscriber`." + ) + } + } let get_parent_name = || { let stack = self.current.lock().unwrap(); let spans = self.spans.lock().unwrap(); @@ -261,9 +1058,11 @@ where cause: ref expected_cause, }) => { if let Some(name) = expected_consequence.name() { + // TODO(hds): Write proper assertion text. assert_eq!(name, consequence_span.name); } if let Some(name) = expected_cause.name() { + // TODO(hds): Write proper assertion text. assert_eq!(name, cause_span.name); } } @@ -309,8 +1108,8 @@ where id.clone(), SpanState { name: meta.name(), - meta, refs: 1, + meta, }, ); id @@ -456,10 +1255,37 @@ where } impl MockHandle { + #[cfg(feature = "tracing-subscriber")] pub(crate) fn new(expected: Arc>>, name: String) -> Self { Self(expected, name) } + /// Checks the expectations which were set on the + /// [`MockSubscriber`]. + /// + /// Calling `assert_finished` is usually the final part of a test. + /// + /// # Panics + /// + /// This method will panic if any of the provided expectations are + /// not met. + /// + /// # Examples + /// + /// ``` + /// use tracing_mock::{subscriber, expect}; + /// + /// let (subscriber, handle) = subscriber::mock() + /// .event(expect::event()) + /// .run_with_handle(); + /// + /// tracing::subscriber::with_default(subscriber, || { + /// tracing::info!("a"); + /// }); + /// + /// // Check assertions set on the mock subscriber + /// handle.assert_finished(); + /// ``` pub fn assert_finished(&self) { if let Ok(ref expected) = self.0.lock() { assert!( @@ -471,51 +1297,3 @@ impl MockHandle { } } } - -impl Expect { - pub(crate) fn bad(&self, name: impl AsRef, what: fmt::Arguments<'_>) { - let name = name.as_ref(); - match self { - Expect::Event(e) => panic!( - "\n[{}] expected event {}\n[{}] but instead {}", - name, e, name, what, - ), - Expect::FollowsFrom { consequence, cause } => panic!( - "\n[{}] expected consequence {} to follow cause {} but instead {}", - name, consequence, cause, what, - ), - Expect::Enter(e) => panic!( - "\n[{}] expected to enter {}\n[{}] but instead {}", - name, e, name, what, - ), - Expect::Exit(e) => panic!( - "\n[{}] expected to exit {}\n[{}] but instead {}", - name, e, name, what, - ), - Expect::CloneSpan(e) => { - panic!( - "\n[{}] expected to clone {}\n[{}] but instead {}", - name, e, name, what, - ) - } - Expect::DropSpan(e) => { - panic!( - "\n[{}] expected to drop {}\n[{}] but instead {}", - name, e, name, what, - ) - } - Expect::Visit(e, fields) => panic!( - "\n[{}] expected {} to record {}\n[{}] but instead {}", - name, e, fields, name, what, - ), - Expect::NewSpan(e) => panic!( - "\n[{}] expected {}\n[{}] but instead {}", - name, e, name, what - ), - Expect::Nothing => panic!( - "\n[{}] expected nothing else to happen\n[{}] but {} instead", - name, name, what, - ), - } - } -} diff --git a/tracing-subscriber/Cargo.toml b/tracing-subscriber/Cargo.toml index 3fbeb2feab..3ee5a99e41 100644 --- a/tracing-subscriber/Cargo.toml +++ b/tracing-subscriber/Cargo.toml @@ -59,6 +59,7 @@ tracing-serde = { path = "../tracing-serde", version = "0.1.3", optional = true # opt-in deps parking_lot = { version = "0.12.1", optional = true } +chrono = { version = "0.4.26", default-features = false, features = ["clock", "std"], optional = true } # registry sharded-slab = { version = "0.1.4", optional = true } diff --git a/tracing-subscriber/src/field/mod.rs b/tracing-subscriber/src/field/mod.rs index 5dfddb3626..03b9146ba6 100644 --- a/tracing-subscriber/src/field/mod.rs +++ b/tracing-subscriber/src/field/mod.rs @@ -55,7 +55,7 @@ pub trait VisitOutput: Visit { /// Extension trait implemented by types which can be recorded by a [visitor]. /// /// This allows writing code that is generic over `tracing_core`'s -/// [`span::Attributes`][attr], [`span::Record`][rec], and [`Event`][event] +/// [`span::Attributes`][attr], [`span::Record`][rec], and [`Event`] /// types. These types all provide inherent `record` methods that allow a /// visitor to record their fields, but there is no common trait representing this. /// @@ -85,7 +85,6 @@ pub trait VisitOutput: Visit { /// [visitor]: tracing_core::field::Visit /// [attr]: tracing_core::span::Attributes /// [rec]: tracing_core::span::Record -/// [event]: tracing_core::event::Event pub trait RecordFields: crate::sealed::Sealed { /// Record all the fields in `self` with the provided `visitor`. fn record(&self, visitor: &mut dyn Visit); diff --git a/tracing-subscriber/src/filter/directive.rs b/tracing-subscriber/src/filter/directive.rs index 2ae3f0f24a..9ee2ce5ad0 100644 --- a/tracing-subscriber/src/filter/directive.rs +++ b/tracing-subscriber/src/filter/directive.rs @@ -49,7 +49,8 @@ enum ParseErrorKind { // === impl DirectiveSet === impl DirectiveSet { - #[cfg(feature = "env-filter")] + // this is only used by `env-filter`. + #[cfg(all(feature = "std", feature = "env-filter"))] pub(crate) fn is_empty(&self) -> bool { self.directives.is_empty() } @@ -397,7 +398,7 @@ impl FromStr for StaticDirective { // === impl ParseError === impl ParseError { - #[cfg(feature = "env-filter")] + #[cfg(all(feature = "std", feature = "env-filter"))] pub(crate) fn new() -> Self { ParseError { kind: ParseErrorKind::Other(None), diff --git a/tracing-subscriber/src/filter/env/builder.rs b/tracing-subscriber/src/filter/env/builder.rs index c814707e6c..8572647412 100644 --- a/tracing-subscriber/src/filter/env/builder.rs +++ b/tracing-subscriber/src/filter/env/builder.rs @@ -212,7 +212,7 @@ impl Builder { #[cfg(feature = "nu_ansi_term")] use nu_ansi_term::{Color, Style}; // NOTE: We can't use a configured `MakeWriter` because the EnvFilter - // has no knowledge of any underlying subscriber or collector, which + // has no knowledge of any underlying subscriber or subscriber, which // may or may not use a `MakeWriter`. let warn = |msg: &str| { #[cfg(not(feature = "nu_ansi_term"))] diff --git a/tracing-subscriber/src/filter/env/directive.rs b/tracing-subscriber/src/filter/env/directive.rs index f062e6ef93..d095065f88 100644 --- a/tracing-subscriber/src/filter/env/directive.rs +++ b/tracing-subscriber/src/filter/env/directive.rs @@ -120,8 +120,9 @@ impl Directive { } pub(super) fn parse(from: &str, regex: bool) -> Result { - static DIRECTIVE_RE: Lazy = Lazy::new(|| Regex::new( - r"(?x) + static DIRECTIVE_RE: Lazy = Lazy::new(|| { + Regex::new( + r"(?x) ^(?P(?i:trace|debug|info|warn|error|off|[0-5]))$ | # ^^^. # `note: we match log level names case-insensitively @@ -135,15 +136,18 @@ impl Directive { # `note: we match log level names case-insensitively )? $ - " - ) - .unwrap()); + ", + ) + .unwrap() + }); static SPAN_PART_RE: Lazy = - Lazy::new(|| Regex::new(r#"(?P[^\]\{]+)?(?:\{(?P[^\}]*)\})?"#).unwrap()); + Lazy::new(|| Regex::new(r"(?P[^\]\{]+)?(?:\{(?P[^\}]*)\})?").unwrap()); static FIELD_FILTER_RE: Lazy = // TODO(eliza): this doesn't _currently_ handle value matchers that include comma // characters. We should fix that. - Lazy::new(|| Regex::new(r#"(?x) + Lazy::new(|| { + Regex::new( + r"(?x) ( # field name [[:word:]][[[:word:]]\.]* @@ -152,7 +156,10 @@ impl Directive { ) # trailing comma or EOS (?:,\s?|$) - "#).unwrap()); + ", + ) + .unwrap() + }); let caps = DIRECTIVE_RE.captures(from).ok_or_else(ParseError::new)?; diff --git a/tracing-subscriber/src/filter/layer_filters/mod.rs b/tracing-subscriber/src/filter/layer_filters/mod.rs index e50ee6f007..69736fafd4 100644 --- a/tracing-subscriber/src/filter/layer_filters/mod.rs +++ b/tracing-subscriber/src/filter/layer_filters/mod.rs @@ -351,10 +351,10 @@ pub trait FilterExt: layer::Filter { // globally applied to events where it doesn't today, since we can't know // what `event_enabled` will say until we have the event to call it with. /// - /// [`Filter`]: crate::subscribe::Filter - /// [`enabled`]: crate::subscribe::Filter::enabled - /// [`event_enabled`]: crate::subscribe::Filter::event_enabled - /// [`callsite_enabled`]: crate::subscribe::Filter::callsite_enabled + /// [`Filter`]: crate::layer::Filter + /// [`enabled`]: crate::layer::Filter::enabled + /// [`event_enabled`]: crate::layer::Filter::event_enabled + /// [`callsite_enabled`]: crate::layer::Filter::callsite_enabled fn not(self) -> combinator::Not where Self: Sized, @@ -478,6 +478,36 @@ macro_rules! filter_impl_body { fn max_level_hint(&self) -> Option { self.deref().max_level_hint() } + + #[inline] + fn event_enabled(&self, event: &Event<'_>, cx: &Context<'_, S>) -> bool { + self.deref().event_enabled(event, cx) + } + + #[inline] + fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { + self.deref().on_new_span(attrs, id, ctx) + } + + #[inline] + fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { + self.deref().on_record(id, values, ctx) + } + + #[inline] + fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { + self.deref().on_enter(id, ctx) + } + + #[inline] + fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { + self.deref().on_exit(id, ctx) + } + + #[inline] + fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { + self.deref().on_close(id, ctx) + } }; } @@ -493,6 +523,75 @@ impl layer::Filter for Box + Send + Sync + 'static> { filter_impl_body!(); } +// Implement Filter for Option where None => allow +#[cfg(feature = "registry")] +#[cfg_attr(docsrs, doc(cfg(feature = "registry")))] +impl layer::Filter for Option +where + F: layer::Filter, +{ + #[inline] + fn enabled(&self, meta: &Metadata<'_>, ctx: &Context<'_, S>) -> bool { + self.as_ref() + .map(|inner| inner.enabled(meta, ctx)) + .unwrap_or(true) + } + + #[inline] + fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest { + self.as_ref() + .map(|inner| inner.callsite_enabled(meta)) + .unwrap_or_else(Interest::always) + } + + #[inline] + fn max_level_hint(&self) -> Option { + self.as_ref().and_then(|inner| inner.max_level_hint()) + } + + #[inline] + fn event_enabled(&self, event: &Event<'_>, ctx: &Context<'_, S>) -> bool { + self.as_ref() + .map(|inner| inner.event_enabled(event, ctx)) + .unwrap_or(true) + } + + #[inline] + fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { + if let Some(inner) = self { + inner.on_new_span(attrs, id, ctx) + } + } + + #[inline] + fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { + if let Some(inner) = self { + inner.on_record(id, values, ctx) + } + } + + #[inline] + fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { + if let Some(inner) = self { + inner.on_enter(id, ctx) + } + } + + #[inline] + fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { + if let Some(inner) = self { + inner.on_exit(id, ctx) + } + } + + #[inline] + fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { + if let Some(inner) = self { + inner.on_close(id, ctx) + } + } +} + // === impl Filtered === impl Filtered { @@ -595,7 +694,7 @@ impl Filtered { /// # } /// ``` /// - /// [subscriber]: Subscribe + /// [`Layer`]: crate::layer::Layer pub fn inner_mut(&mut self) -> &mut L { &mut self.layer } @@ -607,8 +706,8 @@ where F: layer::Filter + 'static, L: Layer, { - fn on_register_dispatch(&self, collector: &Dispatch) { - self.layer.on_register_dispatch(collector); + fn on_register_dispatch(&self, subscriber: &Dispatch) { + self.layer.on_register_dispatch(subscriber); } fn on_layer(&mut self, subscriber: &mut S) { @@ -1091,7 +1190,7 @@ impl FilterState { } } - /// Run a second filtering pass, e.g. for Subscribe::event_enabled. + /// Run a second filtering pass, e.g. for Layer::event_enabled. fn and(&self, filter: FilterId, f: impl FnOnce() -> bool) -> bool { let map = self.enabled.get(); let enabled = map.is_enabled(filter) && f(); diff --git a/tracing-subscriber/src/fmt/fmt_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index 1e0923a547..d3cb8c1ed5 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -5,7 +5,9 @@ use crate::{ registry::{self, LookupSpan, SpanRef}, }; use format::{FmtSpan, TimingDisplay}; -use std::{any::TypeId, cell::RefCell, fmt, io, marker::PhantomData, ops::Deref, time::Instant}; +use std::{ + any::TypeId, cell::RefCell, env, fmt, io, marker::PhantomData, ops::Deref, time::Instant, +}; use tracing_core::{ field, span::{Attributes, Current, Id, Record}, @@ -276,6 +278,15 @@ impl Layer { /// Sets whether or not the formatter emits ANSI terminal escape codes /// for colors and other text formatting. /// + /// When the "ansi" crate feature flag is enabled, ANSI colors are enabled + /// by default unless the [`NO_COLOR`] environment variable is set to + /// a non-empty value. If the [`NO_COLOR`] environment variable is set to + /// any non-empty value, then ANSI colors will be suppressed by default. + /// The [`with_ansi`] and [`set_ansi`] methods can be used to forcibly + /// enable ANSI colors, overriding any [`NO_COLOR`] environment variable. + /// + /// [`NO_COLOR`]: https://no-color.org/ + /// /// Enabling ANSI escapes (calling `with_ansi(true)`) requires the "ansi" /// crate feature flag. Calling `with_ansi(true)` without the "ansi" /// feature flag enabled will panic if debug assertions are enabled, or @@ -288,6 +299,9 @@ impl Layer { /// ANSI escape codes can ensure that they are not used, regardless of /// whether or not other crates in the dependency graph enable the "ansi" /// feature flag. + /// + /// [`with_ansi`]: Subscriber::with_ansi + /// [`set_ansi`]: Subscriber::set_ansi pub fn with_ansi(self, ansi: bool) -> Self { #[cfg(not(feature = "ansi"))] if ansi { @@ -311,10 +325,10 @@ impl Layer { /// By default, `fmt::Layer` will write any `FormatEvent`-internal errors to /// the writer. These errors are unlikely and will only occur if there is a /// bug in the `FormatEvent` implementation or its dependencies. - /// + /// /// If writing to the writer fails, the error message is printed to stderr /// as a fallback. - /// + /// /// [`FormatEvent`]: crate::fmt::FormatEvent pub fn log_internal_errors(self, log_internal_errors: bool) -> Self { Self { @@ -677,12 +691,16 @@ impl Layer { impl Default for Layer { fn default() -> Self { + // only enable ANSI when the feature is enabled, and the NO_COLOR + // environment variable is unset or empty. + let ansi = cfg!(feature = "ansi") && env::var("NO_COLOR").map_or(true, |v| v.is_empty()); + Layer { fmt_fields: format::DefaultFields::default(), fmt_event: format::Format::default(), fmt_span: format::FmtSpanConfig::default(), make_writer: io::stdout, - is_ansi: cfg!(feature = "ansi"), + is_ansi: ansi, log_internal_errors: false, _inner: PhantomData, } @@ -775,7 +793,7 @@ macro_rules! with_event_from_span { #[allow(unused)] let mut iter = fs.iter(); let v = [$( - (&iter.next().unwrap(), Some(&$value as &dyn field::Value)), + (&iter.next().unwrap(), ::core::option::Option::Some(&$value as &dyn field::Value)), )*]; let vs = fs.value_set(&v); let $event = Event::new_child_of($id, meta, &vs); @@ -1288,8 +1306,17 @@ mod test { let actual = sanitize_timings(make_writer.get_string()); // Only assert the start because the line number and callsite may change. - let expected = concat!("Unable to format the following event. Name: event ", file!(), ":"); - assert!(actual.as_str().starts_with(expected), "\nactual = {}\nshould start with expected = {}\n", actual, expected); + let expected = concat!( + "Unable to format the following event. Name: event ", + file!(), + ":" + ); + assert!( + actual.as_str().starts_with(expected), + "\nactual = {}\nshould start with expected = {}\n", + actual, + expected + ); } #[test] @@ -1491,4 +1518,73 @@ mod test { actual.as_str() ); } + + // Because we need to modify an environment variable for these test cases, + // we do them all in a single test. + #[cfg(feature = "ansi")] + #[test] + fn layer_no_color() { + const NO_COLOR: &str = "NO_COLOR"; + + // Restores the previous value of the `NO_COLOR` env variable when + // dropped. + // + // This is done in a `Drop` implementation, rather than just resetting + // the value at the end of the test, so that the previous value is + // restored even if the test panics. + struct RestoreEnvVar(Result); + impl Drop for RestoreEnvVar { + fn drop(&mut self) { + match self.0 { + Ok(ref var) => env::set_var(NO_COLOR, var), + Err(_) => env::remove_var(NO_COLOR), + } + } + } + + let _saved_no_color = RestoreEnvVar(env::var(NO_COLOR)); + + let cases: Vec<(Option<&str>, bool)> = vec![ + (Some("0"), false), // any non-empty value disables ansi + (Some("off"), false), // any non-empty value disables ansi + (Some("1"), false), + (Some(""), true), // empty value does not disable ansi + (None, true), + ]; + + for (var, ansi) in cases { + if let Some(value) = var { + env::set_var(NO_COLOR, value); + } else { + env::remove_var(NO_COLOR); + } + + let layer: Layer<()> = fmt::Layer::default(); + assert_eq!( + layer.is_ansi, ansi, + "NO_COLOR={:?}; Layer::default().is_ansi should be {}", + var, ansi + ); + + // with_ansi should override any `NO_COLOR` value + let layer: Layer<()> = fmt::Layer::default().with_ansi(true); + assert!( + layer.is_ansi, + "NO_COLOR={:?}; Layer::default().with_ansi(true).is_ansi should be true", + var + ); + + // set_ansi should override any `NO_COLOR` value + let mut layer: Layer<()> = fmt::Layer::default(); + layer.set_ansi(true); + assert!( + layer.is_ansi, + "NO_COLOR={:?}; layer.set_ansi(true); layer.is_ansi should be true", + var + ); + } + + // dropping `_saved_no_color` will restore the previous value of + // `NO_COLOR`. + } } diff --git a/tracing-subscriber/src/fmt/format/mod.rs b/tracing-subscriber/src/fmt/format/mod.rs index fa22c78ec8..ee56c5c2d1 100644 --- a/tracing-subscriber/src/fmt/format/mod.rs +++ b/tracing-subscriber/src/fmt/format/mod.rs @@ -326,8 +326,10 @@ pub struct FieldFnVisitor<'a, F> { /// Marker for [`Format`] that indicates that the compact log format should be used. /// /// The compact format includes fields from all currently entered spans, after -/// the event's fields. Span names are listed in order before fields are -/// displayed. +/// the event's fields. Span fields are ordered (but not grouped) by +/// span, and span names are not shown. A more compact representation of the +/// event's [`Level`] is used, and additional information—such as the event's +/// target—is disabled by default. /// /// # Example Output /// @@ -1086,7 +1088,12 @@ where let mut needs_space = false; if self.display_target { - write!(writer, "{}{}", dimmed.paint(meta.target()), dimmed.paint(":"))?; + write!( + writer, + "{}{}", + dimmed.paint(meta.target()), + dimmed.paint(":") + )?; needs_space = true; } diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index cfe4704758..163b56da3f 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -762,7 +762,7 @@ where /// Sets the subscriber being built to use a JSON formatter. /// - /// See [`format::Json`][super::fmt::format::Json] + /// See [`format::Json`] for details. #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn json( @@ -783,7 +783,7 @@ where impl SubscriberBuilder, F, W> { /// Sets the json subscriber being built to flatten event metadata. /// - /// See [`format::Json`][super::fmt::format::Json] + /// See [`format::Json`] for details. pub fn flatten_event( self, flatten_event: bool, @@ -797,7 +797,7 @@ impl SubscriberBuilder SubscriberBuilder MutexGuard<'_, Vec> { self.buf.lock().unwrap() diff --git a/tracing-subscriber/src/fmt/time/chrono_crate.rs b/tracing-subscriber/src/fmt/time/chrono_crate.rs new file mode 100644 index 0000000000..1a831efa1b --- /dev/null +++ b/tracing-subscriber/src/fmt/time/chrono_crate.rs @@ -0,0 +1,177 @@ +use crate::fmt::format::Writer; +use crate::fmt::time::FormatTime; + +use std::sync::Arc; + +/// Formats [local time]s and [UTC time]s with `FormatTime` implementations +/// that use the [`chrono` crate]. +/// +/// [local time]: [`chrono::offset::Local`] +/// [UTC time]: [`chrono::offset::Utc`] +/// [`chrono` crate]: [`chrono`] + +/// Formats the current [local time] using a [formatter] from the [`chrono`] crate. +/// +/// [local time]: chrono::Local::now() +/// [formatter]: chrono::format +#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct ChronoLocal { + format: Arc, +} + +impl ChronoLocal { + /// Format the time using the [`RFC 3339`] format + /// (a subset of [`ISO 8601`]). + /// + /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339 + /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601 + pub fn rfc_3339() -> Self { + Self { + format: Arc::new(ChronoFmtType::Rfc3339), + } + } + + /// Format the time using the given format string. + /// + /// See [`chrono::format::strftime`] for details on the supported syntax. + pub fn new(format_string: String) -> Self { + Self { + format: Arc::new(ChronoFmtType::Custom(format_string)), + } + } +} + +impl FormatTime for ChronoLocal { + fn format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result { + let t = chrono::Local::now(); + match self.format.as_ref() { + ChronoFmtType::Rfc3339 => { + use chrono::format::{Fixed, Item}; + write!( + w, + "{}", + t.format_with_items(core::iter::once(Item::Fixed(Fixed::RFC3339))) + ) + } + ChronoFmtType::Custom(fmt) => { + write!(w, "{}", t.format(fmt)) + } + } + } +} + +/// Formats the current [UTC time] using a [formatter] from the [`chrono`] crate. +/// +/// [UTC time]: chrono::Utc::now() +/// [formatter]: chrono::format +#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct ChronoUtc { + format: Arc, +} + +impl ChronoUtc { + /// Format the time using the [`RFC 3339`] format + /// (a subset of [`ISO 8601`]). + /// + /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339 + /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601 + pub fn rfc_3339() -> Self { + Self { + format: Arc::new(ChronoFmtType::Rfc3339), + } + } + + /// Format the time using the given format string. + /// + /// See [`chrono::format::strftime`] for details on the supported syntax. + pub fn new(format_string: String) -> Self { + Self { + format: Arc::new(ChronoFmtType::Custom(format_string)), + } + } +} + +impl FormatTime for ChronoUtc { + fn format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result { + let t = chrono::Utc::now(); + match self.format.as_ref() { + ChronoFmtType::Rfc3339 => w.write_str(&t.to_rfc3339()), + ChronoFmtType::Custom(fmt) => w.write_str(&format!("{}", t.format(fmt))), + } + } +} + +/// The RFC 3339 format is used by default but a custom format string +/// can be used. See [`chrono::format::strftime`]for details on +/// the supported syntax. +/// +/// [`chrono::format::strftime`]: https://docs.rs/chrono/0.4.9/chrono/format/strftime/index.html +#[derive(Debug, Clone, Eq, PartialEq)] +enum ChronoFmtType { + /// Format according to the RFC 3339 convention. + Rfc3339, + /// Format according to a custom format string. + Custom(String), +} + +impl Default for ChronoFmtType { + fn default() -> Self { + ChronoFmtType::Rfc3339 + } +} + +#[cfg(test)] +mod tests { + use crate::fmt::format::Writer; + use crate::fmt::time::FormatTime; + + use std::sync::Arc; + + use super::ChronoFmtType; + use super::ChronoLocal; + use super::ChronoUtc; + + #[test] + fn test_chrono_format_time_utc_default() { + let mut buf = String::new(); + let mut dst: Writer<'_> = Writer::new(&mut buf); + assert!(FormatTime::format_time(&ChronoUtc::default(), &mut dst).is_ok()); + // e.g. `buf` contains "2023-08-18T19:05:08.662499+00:00" + assert!(chrono::DateTime::parse_from_str(&buf, "%FT%H:%M:%S%.6f%z").is_ok()); + } + + #[test] + fn test_chrono_format_time_utc_custom() { + let fmt = ChronoUtc { + format: Arc::new(ChronoFmtType::Custom("%a %b %e %T %Y".to_owned())), + }; + let mut buf = String::new(); + let mut dst: Writer<'_> = Writer::new(&mut buf); + assert!(FormatTime::format_time(&fmt, &mut dst).is_ok()); + // e.g. `buf` contains "Wed Aug 23 15:53:23 2023" + assert!(chrono::NaiveDateTime::parse_from_str(&buf, "%a %b %e %T %Y").is_ok()); + } + + #[test] + fn test_chrono_format_time_local_default() { + let mut buf = String::new(); + let mut dst: Writer<'_> = Writer::new(&mut buf); + assert!(FormatTime::format_time(&ChronoLocal::default(), &mut dst).is_ok()); + // e.g. `buf` contains "2023-08-18T14:59:08.662499-04:00". + assert!(chrono::DateTime::parse_from_str(&buf, "%FT%H:%M:%S%.6f%z").is_ok()); + } + + #[test] + fn test_chrono_format_time_local_custom() { + let fmt = ChronoLocal { + format: Arc::new(ChronoFmtType::Custom("%a %b %e %T %Y".to_owned())), + }; + let mut buf = String::new(); + let mut dst: Writer<'_> = Writer::new(&mut buf); + assert!(FormatTime::format_time(&fmt, &mut dst).is_ok()); + // e.g. `buf` contains "Wed Aug 23 15:55:46 2023". + assert!(chrono::NaiveDateTime::parse_from_str(&buf, "%a %b %e %T %Y").is_ok()); + } +} diff --git a/tracing-subscriber/src/fmt/time/mod.rs b/tracing-subscriber/src/fmt/time/mod.rs index 1d1bba2406..48f34d18d2 100644 --- a/tracing-subscriber/src/fmt/time/mod.rs +++ b/tracing-subscriber/src/fmt/time/mod.rs @@ -7,6 +7,7 @@ mod datetime; #[cfg(feature = "time")] mod time_crate; + #[cfg(feature = "time")] #[cfg_attr(docsrs, doc(cfg(feature = "time")))] pub use time_crate::UtcTime; @@ -19,6 +20,18 @@ pub use time_crate::LocalTime; #[cfg_attr(docsrs, doc(cfg(feature = "time")))] pub use time_crate::OffsetTime; +/// [`chrono`]-based implementation for [`FormatTime`]. +#[cfg(feature = "chrono")] +mod chrono_crate; + +#[cfg(feature = "chrono")] +#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] +pub use chrono_crate::ChronoLocal; + +#[cfg(feature = "chrono")] +#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] +pub use chrono_crate::ChronoUtc; + /// A type that can measure and format the current time. /// /// This trait is used by `Format` to include a timestamp with each `Event` when it is logged. @@ -52,7 +65,7 @@ pub trait FormatTime { /// # } /// ``` pub fn time() -> SystemTime { - SystemTime::default() + SystemTime } /// Returns a new `Uptime` timestamp provider. diff --git a/tracing-subscriber/src/fmt/time/time_crate.rs b/tracing-subscriber/src/fmt/time/time_crate.rs index 60d57fd0bc..4883db418d 100644 --- a/tracing-subscriber/src/fmt/time/time_crate.rs +++ b/tracing-subscriber/src/fmt/time/time_crate.rs @@ -76,9 +76,9 @@ impl LocalTime { /// ``` /// use tracing_subscriber::fmt::{self, time}; /// - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(time::LocalTime::rfc_3339()); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// [local time]: time::OffsetDateTime::now_local @@ -130,9 +130,9 @@ impl LocalTime { /// use time::macros::format_description; /// /// let timer = LocalTime::new(format_description!("[hour]:[minute]:[second]")); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using [`time::format_description::parse`]: @@ -143,9 +143,9 @@ impl LocalTime { /// let time_format = time::format_description::parse("[hour]:[minute]:[second]") /// .expect("format string should be valid!"); /// let timer = LocalTime::new(time_format); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using the [`format_description!`] macro requires enabling the `time` @@ -158,9 +158,9 @@ impl LocalTime { /// use tracing_subscriber::fmt::{self, time::LocalTime}; /// /// let timer = LocalTime::new(time::format_description::well_known::Rfc3339); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// [local time]: time::OffsetDateTime::now_local() @@ -207,9 +207,9 @@ impl UtcTime { /// ``` /// use tracing_subscriber::fmt::{self, time}; /// - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(time::UtcTime::rfc_3339()); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// [local time]: time::OffsetDateTime::now_utc @@ -247,9 +247,9 @@ impl UtcTime { /// use time::macros::format_description; /// /// let timer = UtcTime::new(format_description!("[hour]:[minute]:[second]")); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using the [`format_description!`] macro requires enabling the `time` @@ -263,9 +263,9 @@ impl UtcTime { /// let time_format = time::format_description::parse("[hour]:[minute]:[second]") /// .expect("format string should be valid!"); /// let timer = UtcTime::new(time_format); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using a [well-known format][well-known formats] (this is equivalent to @@ -275,9 +275,9 @@ impl UtcTime { /// use tracing_subscriber::fmt::{self, time::UtcTime}; /// /// let timer = UtcTime::new(time::format_description::well_known::Rfc3339); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// [UTC time]: time::OffsetDateTime::now_utc() @@ -326,9 +326,9 @@ impl OffsetTime { /// ``` /// use tracing_subscriber::fmt::{self, time}; /// - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(time::OffsetTime::local_rfc_3339().expect("could not get local offset!")); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using `OffsetTime` with Tokio: @@ -398,9 +398,9 @@ impl OffsetTime { /// /// let offset = UtcOffset::current_local_offset().expect("should get local offset!"); /// let timer = OffsetTime::new(offset, format_description!("[hour]:[minute]:[second]")); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using [`time::format_description::parse`]: @@ -413,9 +413,9 @@ impl OffsetTime { /// let time_format = time::format_description::parse("[hour]:[minute]:[second]") /// .expect("format string should be valid!"); /// let timer = OffsetTime::new(offset, time_format); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// Using the [`format_description!`] macro requires enabling the `time` @@ -430,9 +430,9 @@ impl OffsetTime { /// /// let offset = UtcOffset::current_local_offset().expect("should get local offset!"); /// let timer = OffsetTime::new(offset, time::format_description::well_known::Rfc3339); - /// let collector = tracing_subscriber::fmt() + /// let subscriber = tracing_subscriber::fmt() /// .with_timer(timer); - /// # drop(collector); + /// # drop(subscriber); /// ``` /// /// [`time` crate]: time diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index 2b9f9e973e..bbc1c4a298 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -16,7 +16,7 @@ use tracing_core::Metadata; /// This trait is already implemented for function pointers and /// immutably-borrowing closures that return an instance of [`io::Write`], such /// as [`io::stdout`] and [`io::stderr`]. Additionally, it is implemented for -/// [`std::sync::Mutex`][mutex] when the type inside the mutex implements +/// [`std::sync::Mutex`] when the type inside the mutex implements /// [`io::Write`]. /// /// # Examples @@ -66,7 +66,7 @@ use tracing_core::Metadata; /// ``` /// /// A single instance of a type implementing [`io::Write`] may be used as a -/// `MakeWriter` by wrapping it in a [`Mutex`][mutex]. For example, we could +/// `MakeWriter` by wrapping it in a [`Mutex`]. For example, we could /// write to a file like so: /// /// ``` @@ -88,7 +88,6 @@ use tracing_core::Metadata; /// [`Event`]: tracing_core::event::Event /// [`io::stdout`]: std::io::stdout() /// [`io::stderr`]: std::io::stderr() -/// [mutex]: std::sync::Mutex /// [`MakeWriter::make_writer_for`]: MakeWriter::make_writer_for /// [`Metadata`]: tracing_core::Metadata /// [levels]: tracing_core::Level @@ -325,7 +324,7 @@ pub trait MakeWriterExt<'a>: MakeWriter<'a> { /// Wraps `self` with a predicate that takes a span or event's [`Metadata`] /// and returns a `bool`. The returned [`MakeWriter`]'s - /// [`MakeWriter::make_writer_for`][mwf] method will check the predicate to + /// [`MakeWriter::make_writer_for`] method will check the predicate to /// determine if a writer should be produced for a given span or event. /// /// If the predicate returns `false`, the wrapped [`MakeWriter`]'s @@ -544,7 +543,7 @@ pub struct BoxMakeWriter { name: &'static str, } -/// A [writer] that is one of two types implementing [`io::Write`][writer]. +/// A [writer] that is one of two types implementing [`io::Write`]. /// /// This may be used by [`MakeWriter`] implementations that may conditionally /// return one of two writers. diff --git a/tracing-subscriber/src/layer/layered.rs b/tracing-subscriber/src/layer/layered.rs index f09c58c97c..e276514986 100644 --- a/tracing-subscriber/src/layer/layered.rs +++ b/tracing-subscriber/src/layer/layered.rs @@ -470,7 +470,7 @@ where return Interest::sometimes(); } - // otherwise, allow the inner subscriber or collector to weigh in. + // otherwise, allow the inner subscriber or subscriber to weigh in. inner } diff --git a/tracing-subscriber/src/layer/mod.rs b/tracing-subscriber/src/layer/mod.rs index bdc154301a..296de5ef48 100644 --- a/tracing-subscriber/src/layer/mod.rs +++ b/tracing-subscriber/src/layer/mod.rs @@ -468,6 +468,24 @@ //! function pointer. In addition, when more control is required, the [`Filter`] //! trait may also be implemented for user-defined types. //! +//! //! [`Option`] also implements [`Filter`], which allows for an optional +//! filter. [`None`](Option::None) filters out _nothing_ (that is, allows +//! everything through). For example: +//! +//! ```rust +//! # use tracing_subscriber::{filter::filter_fn, Layer}; +//! # use tracing_core::{Metadata, subscriber::Subscriber}; +//! # struct MyLayer(std::marker::PhantomData); +//! # impl MyLayer { fn new() -> Self { Self(std::marker::PhantomData)} } +//! # impl Layer for MyLayer {} +//! # fn my_filter(_: &str) -> impl Fn(&Metadata) -> bool { |_| true } +//! fn setup_tracing(filter_config: Option<&str>) { +//! let layer = MyLayer::::new() +//! .with_filter(filter_config.map(|config| filter_fn(my_filter(config)))); +//! //... +//! } +//! ``` +//! //!
 //!     Warning: Currently, the 
 //!     Registry type defined in this crate is the only root
@@ -732,8 +750,8 @@ where
     /// [`WeakDispatch`]: tracing_core::dispatcher::WeakDispatch
     /// [upgraded]: tracing_core::dispatcher::WeakDispatch::upgrade
     /// [`Subscriber`]: tracing_core::Subscriber
-    fn on_register_dispatch(&self, collector: &Dispatch) {
-        let _ = collector;
+    fn on_register_dispatch(&self, subscriber: &Dispatch) {
+        let _ = subscriber;
     }
 
     /// Performs late initialization when attaching a `Layer` to a
diff --git a/tracing-subscriber/src/macros.rs b/tracing-subscriber/src/macros.rs
index 81351132f5..5b461d0a0a 100644
--- a/tracing-subscriber/src/macros.rs
+++ b/tracing-subscriber/src/macros.rs
@@ -4,7 +4,7 @@ macro_rules! try_lock {
         try_lock!($lock, else return)
     };
     ($lock:expr, else $els:expr) => {
-        if let Ok(l) = $lock {
+        if let ::core::result::Result::Ok(l) = $lock {
             l
         } else if std::thread::panicking() {
             $els
diff --git a/tracing-subscriber/src/registry/mod.rs b/tracing-subscriber/src/registry/mod.rs
index 38af53e8ad..1617f5ce4f 100644
--- a/tracing-subscriber/src/registry/mod.rs
+++ b/tracing-subscriber/src/registry/mod.rs
@@ -200,11 +200,9 @@ pub trait SpanData<'a> {
 
 /// A reference to [span data] and the associated [registry].
 ///
-/// This type implements all the same methods as [`SpanData`][span data], and
-/// provides additional methods for querying the registry based on values from
-/// the span.
+/// This type implements all the same methods as [`SpanData`], and provides
+/// additional methods for querying the registry based on values from the span.
 ///
-/// [span data]: SpanData
 /// [registry]: LookupSpan
 #[derive(Debug)]
 pub struct SpanRef<'a, R: LookupSpan<'a>> {
diff --git a/tracing-subscriber/tests/cached_layer_filters_dont_break_other_layers.rs b/tracing-subscriber/tests/cached_layer_filters_dont_break_other_layers.rs
index 5b40b60aa3..b6d767739d 100644
--- a/tracing-subscriber/tests/cached_layer_filters_dont_break_other_layers.rs
+++ b/tracing-subscriber/tests/cached_layer_filters_dont_break_other_layers.rs
@@ -1,7 +1,7 @@
 #![cfg(feature = "registry")]
 use tracing::Level;
 use tracing_mock::{
-    event,
+    expect,
     layer::{self, MockLayer},
     subscriber,
 };
@@ -107,20 +107,20 @@ fn filter() -> LevelFilter {
 
 fn unfiltered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
 
 fn filtered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
diff --git a/tracing-subscriber/tests/env_filter/main.rs b/tracing-subscriber/tests/env_filter/main.rs
index ef984a68a9..16921814c1 100644
--- a/tracing-subscriber/tests/env_filter/main.rs
+++ b/tracing-subscriber/tests/env_filter/main.rs
@@ -3,20 +3,21 @@
 mod per_layer;
 
 use tracing::{self, subscriber::with_default, Level};
-use tracing_mock::{event, field, layer, span, subscriber};
+use tracing_mock::{expect, layer, span, subscriber};
 use tracing_subscriber::{
     filter::{EnvFilter, LevelFilter},
     prelude::*,
+    Registry,
 };
 
 #[test]
 fn level_filter_event() {
     let filter: EnvFilter = "info".parse().expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -38,18 +39,18 @@ fn same_name_spans() {
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("bar")),
+                .with_field(expect::field("bar")),
         )
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("baz")),
+                .with_field(expect::field("baz")),
         )
-        .done()
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
     with_default(subscriber, || {
@@ -64,12 +65,12 @@ fn same_name_spans() {
 fn level_filter_event_with_target() {
     let filter: EnvFilter = "info,stuff=debug".parse().expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-        .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+        .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -95,20 +96,20 @@ fn level_filter_event_with_target_and_span_global() {
 
     let cool_span = span::named("cool_span");
     let uncool_span = span::named("uncool_span");
-    let (subscriber, handle) = subscriber::mock()
+    let (layer, handle) = layer::mock()
         .enter(cool_span.clone())
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
                 .in_scope(vec![cool_span.clone()]),
         )
         .exit(cool_span)
         .enter(uncool_span.clone())
         .exit(uncool_span)
-        .done()
+        .only()
         .run_with_handle();
 
-    let subscriber = subscriber.with(filter);
+    let subscriber = Registry::default().with(filter).with(layer);
 
     with_default(subscriber, || {
         {
@@ -133,12 +134,12 @@ fn not_order_dependent() {
 
     let filter: EnvFilter = "stuff=debug,info".parse().expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-        .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+        .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -167,9 +168,9 @@ fn add_directive_enables_event() {
     filter = filter.add_directive("hello=trace".parse().expect("directive should parse"));
 
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO).with_target("hello"))
-        .event(event::mock().at_level(Level::TRACE).with_target("hello"))
-        .done()
+        .event(expect::event().at_level(Level::INFO).with_target("hello"))
+        .event(expect::event().at_level(Level::TRACE).with_target("hello"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -187,19 +188,19 @@ fn span_name_filter_is_dynamic() {
         .parse()
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .enter(span::named("cool_span"))
-        .event(event::mock().at_level(Level::DEBUG))
-        .enter(span::named("uncool_span"))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::DEBUG))
-        .exit(span::named("uncool_span"))
-        .exit(span::named("cool_span"))
-        .enter(span::named("uncool_span"))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .exit(span::named("uncool_span"))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .enter(expect::span().named("cool_span"))
+        .event(expect::event().at_level(Level::DEBUG))
+        .enter(expect::span().named("uncool_span"))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::DEBUG))
+        .exit(expect::span().named("uncool_span"))
+        .exit(expect::span().named("cool_span"))
+        .enter(expect::span().named("uncool_span"))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .exit(expect::span().named("uncool_span"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -245,10 +246,10 @@ mod per_layer_filter {
     fn level_filter_event() {
         let filter: EnvFilter = "info".parse().expect("filter should parse");
         let (layer, handle) = layer::mock()
-            .event(event::mock().at_level(Level::INFO))
-            .event(event::mock().at_level(Level::WARN))
-            .event(event::mock().at_level(Level::ERROR))
-            .done()
+            .event(expect::event().at_level(Level::INFO))
+            .event(expect::event().at_level(Level::WARN))
+            .event(expect::event().at_level(Level::ERROR))
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -271,18 +272,18 @@ mod per_layer_filter {
             .expect("filter should parse");
         let (layer, handle) = layer::mock()
             .new_span(
-                span::mock()
+                expect::span()
                     .named("foo")
                     .at_level(Level::TRACE)
-                    .with_field(field::mock("bar")),
+                    .with_field(expect::field("bar")),
             )
             .new_span(
-                span::mock()
+                expect::span()
                     .named("foo")
                     .at_level(Level::TRACE)
-                    .with_field(field::mock("baz")),
+                    .with_field(expect::field("baz")),
             )
-            .done()
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -299,12 +300,12 @@ mod per_layer_filter {
     fn level_filter_event_with_target() {
         let filter: EnvFilter = "info,stuff=debug".parse().expect("filter should parse");
         let (layer, handle) = layer::mock()
-            .event(event::mock().at_level(Level::INFO))
-            .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-            .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-            .event(event::mock().at_level(Level::ERROR))
-            .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-            .done()
+            .event(expect::event().at_level(Level::INFO))
+            .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+            .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+            .event(expect::event().at_level(Level::ERROR))
+            .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -333,12 +334,12 @@ mod per_layer_filter {
         let (layer, handle) = layer::mock()
             .enter(cool_span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::DEBUG)
                     .in_scope(vec![cool_span.clone()]),
             )
             .exit(cool_span)
-            .done()
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -366,12 +367,12 @@ mod per_layer_filter {
 
         let filter: EnvFilter = "stuff=debug,info".parse().expect("filter should parse");
         let (layer, finished) = layer::mock()
-            .event(event::mock().at_level(Level::INFO))
-            .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-            .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-            .event(event::mock().at_level(Level::ERROR))
-            .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-            .done()
+            .event(expect::event().at_level(Level::INFO))
+            .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+            .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+            .event(expect::event().at_level(Level::ERROR))
+            .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -401,9 +402,9 @@ mod per_layer_filter {
         filter = filter.add_directive("hello=trace".parse().expect("directive should parse"));
 
         let (layer, finished) = layer::mock()
-            .event(event::mock().at_level(Level::INFO).with_target("hello"))
-            .event(event::mock().at_level(Level::TRACE).with_target("hello"))
-            .done()
+            .event(expect::event().at_level(Level::INFO).with_target("hello"))
+            .event(expect::event().at_level(Level::TRACE).with_target("hello"))
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -424,21 +425,21 @@ mod per_layer_filter {
         let cool_span = span::named("cool_span");
         let uncool_span = span::named("uncool_span");
         let (layer, finished) = layer::mock()
-            .event(event::mock().at_level(Level::INFO))
+            .event(expect::event().at_level(Level::INFO))
             .enter(cool_span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::DEBUG)
                     .in_scope(vec![cool_span.clone()]),
             )
             .enter(uncool_span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::WARN)
                     .in_scope(vec![uncool_span.clone()]),
             )
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::DEBUG)
                     .in_scope(vec![uncool_span.clone()]),
             )
@@ -446,17 +447,17 @@ mod per_layer_filter {
             .exit(cool_span)
             .enter(uncool_span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::WARN)
                     .in_scope(vec![uncool_span.clone()]),
             )
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::ERROR)
                     .in_scope(vec![uncool_span.clone()]),
             )
             .exit(uncool_span)
-            .done()
+            .only()
             .run_with_handle();
 
         let _subscriber = tracing_subscriber::registry()
@@ -497,12 +498,12 @@ mod per_layer_filter {
             let (layer, handle) = layer::named("layer1")
                 .enter(span.clone())
                 .event(
-                    event::mock()
+                    expect::event()
                         .at_level(Level::DEBUG)
                         .in_scope(vec![span.clone()]),
                 )
                 .exit(span)
-                .done()
+                .only()
                 .run_with_handle();
             (layer.with_filter(filter), handle)
         };
@@ -513,12 +514,12 @@ mod per_layer_filter {
             let (layer, handle) = layer::named("layer2")
                 .enter(span.clone())
                 .event(
-                    event::mock()
+                    expect::event()
                         .at_level(Level::INFO)
                         .in_scope(vec![span.clone()]),
                 )
                 .exit(span)
-                .done()
+                .only()
                 .run_with_handle();
             (layer.with_filter(filter), handle)
         };
diff --git a/tracing-subscriber/tests/env_filter/per_layer.rs b/tracing-subscriber/tests/env_filter/per_layer.rs
index 4b143b8bfd..229b9ff776 100644
--- a/tracing-subscriber/tests/env_filter/per_layer.rs
+++ b/tracing-subscriber/tests/env_filter/per_layer.rs
@@ -2,16 +2,16 @@
 //! `Layer` filter).
 #![cfg(feature = "registry")]
 use super::*;
-use tracing_mock::{event, field, layer, span};
+use tracing_mock::{layer, span};
 
 #[test]
 fn level_filter_event() {
     let filter: EnvFilter = "info".parse().expect("filter should parse");
     let (layer, handle) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -34,18 +34,18 @@ fn same_name_spans() {
         .expect("filter should parse");
     let (layer, handle) = layer::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("bar")),
+                .with_field(expect::field("bar")),
         )
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("baz")),
+                .with_field(expect::field("baz")),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -62,12 +62,12 @@ fn same_name_spans() {
 fn level_filter_event_with_target() {
     let filter: EnvFilter = "info,stuff=debug".parse().expect("filter should parse");
     let (layer, handle) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-        .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+        .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -96,12 +96,12 @@ fn level_filter_event_with_target_and_span() {
     let (layer, handle) = layer::mock()
         .enter(cool_span.clone())
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
                 .in_scope(vec![cool_span.clone()]),
         )
         .exit(cool_span)
-        .done()
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -129,12 +129,12 @@ fn not_order_dependent() {
 
     let filter: EnvFilter = "stuff=debug,info".parse().expect("filter should parse");
     let (layer, finished) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::DEBUG).with_target("stuff"))
-        .event(event::mock().at_level(Level::WARN).with_target("stuff"))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::ERROR).with_target("stuff"))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG).with_target("stuff"))
+        .event(expect::event().at_level(Level::WARN).with_target("stuff"))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::ERROR).with_target("stuff"))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -164,9 +164,9 @@ fn add_directive_enables_event() {
     filter = filter.add_directive("hello=trace".parse().expect("directive should parse"));
 
     let (layer, finished) = layer::mock()
-        .event(event::mock().at_level(Level::INFO).with_target("hello"))
-        .event(event::mock().at_level(Level::TRACE).with_target("hello"))
-        .done()
+        .event(expect::event().at_level(Level::INFO).with_target("hello"))
+        .event(expect::event().at_level(Level::TRACE).with_target("hello"))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -187,21 +187,21 @@ fn span_name_filter_is_dynamic() {
     let cool_span = span::named("cool_span");
     let uncool_span = span::named("uncool_span");
     let (layer, finished) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::INFO))
         .enter(cool_span.clone())
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
                 .in_scope(vec![cool_span.clone()]),
         )
         .enter(uncool_span.clone())
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::WARN)
                 .in_scope(vec![uncool_span.clone()]),
         )
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
                 .in_scope(vec![uncool_span.clone()]),
         )
@@ -209,17 +209,17 @@ fn span_name_filter_is_dynamic() {
         .exit(cool_span)
         .enter(uncool_span.clone())
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::WARN)
                 .in_scope(vec![uncool_span.clone()]),
         )
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::ERROR)
                 .in_scope(vec![uncool_span.clone()]),
         )
         .exit(uncool_span)
-        .done()
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -260,12 +260,12 @@ fn multiple_dynamic_filters() {
         let (layer, handle) = layer::named("layer1")
             .enter(span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::DEBUG)
                     .in_scope(vec![span.clone()]),
             )
             .exit(span)
-            .done()
+            .only()
             .run_with_handle();
         (layer.with_filter(filter), handle)
     };
@@ -276,12 +276,12 @@ fn multiple_dynamic_filters() {
         let (layer, handle) = layer::named("layer2")
             .enter(span.clone())
             .event(
-                event::mock()
+                expect::event()
                     .at_level(Level::INFO)
                     .in_scope(vec![span.clone()]),
             )
             .exit(span)
-            .done()
+            .only()
             .run_with_handle();
         (layer.with_filter(filter), handle)
     };
diff --git a/tracing-subscriber/tests/field_filter.rs b/tracing-subscriber/tests/field_filter.rs
index 385d024f65..b14aebc421 100644
--- a/tracing-subscriber/tests/field_filter.rs
+++ b/tracing-subscriber/tests/field_filter.rs
@@ -10,16 +10,16 @@ fn field_filter_events() {
     let filter: EnvFilter = "[{thing}]=debug".parse().expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::INFO)
-                .with_fields(field::mock("thing")),
+                .with_fields(expect::field("thing")),
         )
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
-                .with_fields(field::mock("thing")),
+                .with_fields(expect::field("thing")),
         )
-        .done()
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -41,23 +41,23 @@ fn field_filter_spans() {
         .parse()
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .enter(span::mock().named("span1"))
+        .enter(expect::span().named("span1"))
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::INFO)
-                .with_fields(field::mock("something")),
+                .with_fields(expect::field("something")),
         )
-        .exit(span::mock().named("span1"))
-        .enter(span::mock().named("span2"))
-        .exit(span::mock().named("span2"))
-        .enter(span::mock().named("span3"))
+        .exit(expect::span().named("span1"))
+        .enter(expect::span().named("span2"))
+        .exit(expect::span().named("span2"))
+        .enter(expect::span().named("span3"))
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::DEBUG)
-                .with_fields(field::mock("something")),
+                .with_fields(expect::field("something")),
         )
-        .exit(span::mock().named("span3"))
-        .done()
+        .exit(expect::span().named("span3"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -84,16 +84,16 @@ fn record_after_created() {
         .parse()
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .enter(span::mock().named("span"))
-        .exit(span::mock().named("span"))
+        .enter(expect::span().named("span"))
+        .exit(expect::span().named("span"))
         .record(
-            span::mock().named("span"),
-            field::mock("enabled").with_value(&true),
+            expect::span().named("span"),
+            expect::field("enabled").with_value(&true),
         )
-        .enter(span::mock().named("span"))
-        .event(event::mock().at_level(Level::DEBUG))
-        .exit(span::mock().named("span"))
-        .done()
+        .enter(expect::span().named("span"))
+        .event(expect::event().at_level(Level::DEBUG))
+        .exit(expect::span().named("span"))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
diff --git a/tracing-subscriber/tests/filter_log.rs b/tracing-subscriber/tests/filter_log.rs
index 8d57ed600b..9cda4340e4 100644
--- a/tracing-subscriber/tests/filter_log.rs
+++ b/tracing-subscriber/tests/filter_log.rs
@@ -36,10 +36,10 @@ fn log_is_enabled() {
         .parse()
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     // Note: we have to set the global default in order to set the `log` max
diff --git a/tracing-subscriber/tests/hinted_layer_filters_dont_break_other_layers.rs b/tracing-subscriber/tests/hinted_layer_filters_dont_break_other_layers.rs
index 4e5ee4e050..a3ad351580 100644
--- a/tracing-subscriber/tests/hinted_layer_filters_dont_break_other_layers.rs
+++ b/tracing-subscriber/tests/hinted_layer_filters_dont_break_other_layers.rs
@@ -1,9 +1,9 @@
 #![cfg(feature = "registry")]
 use tracing::{Level, Metadata, Subscriber};
 use tracing_mock::{
-    event,
-    layer::{self, MockLayer},
-    subscriber,
+    expect, layer,
+    layer::MockLayer,
+    subscriber::{self},
 };
 use tracing_subscriber::{filter::DynFilterFn, layer::Context, prelude::*};
 
@@ -115,20 +115,20 @@ fn filter() -> DynFilterFn {
 
 fn unfiltered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
 
 fn filtered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
diff --git a/tracing-subscriber/tests/layer_filter_interests_are_cached.rs b/tracing-subscriber/tests/layer_filter_interests_are_cached.rs
index 67e8ba763c..867fdd0717 100644
--- a/tracing-subscriber/tests/layer_filter_interests_are_cached.rs
+++ b/tracing-subscriber/tests/layer_filter_interests_are_cached.rs
@@ -4,7 +4,7 @@ use std::{
     sync::{Arc, Mutex},
 };
 use tracing::{Level, Subscriber};
-use tracing_mock::{event, layer};
+use tracing_mock::{expect, layer};
 use tracing_subscriber::{filter, prelude::*};
 
 #[test]
@@ -21,9 +21,9 @@ fn layer_filter_interests_are_cached() {
     });
 
     let (expect, handle) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let subscriber = tracing_subscriber::registry().with(expect.with_filter(filter));
diff --git a/tracing-subscriber/tests/layer_filters/boxed.rs b/tracing-subscriber/tests/layer_filters/boxed.rs
index b02331a6c3..96566a5441 100644
--- a/tracing-subscriber/tests/layer_filters/boxed.rs
+++ b/tracing-subscriber/tests/layer_filters/boxed.rs
@@ -3,7 +3,7 @@ use tracing_mock::layer::MockLayer;
 use tracing_subscriber::{filter, prelude::*, Layer};
 
 fn layer() -> (MockLayer, subscriber::MockHandle) {
-    layer::mock().done().run_with_handle()
+    layer::mock().only().run_with_handle()
 }
 
 fn filter() -> filter::DynFilterFn {
diff --git a/tracing-subscriber/tests/layer_filters/combinators.rs b/tracing-subscriber/tests/layer_filters/combinators.rs
index 6052a2d00c..c5ea3b5151 100644
--- a/tracing-subscriber/tests/layer_filters/combinators.rs
+++ b/tracing-subscriber/tests/layer_filters/combinators.rs
@@ -12,7 +12,7 @@ fn and() {
                 .at_level(tracing::Level::INFO)
                 .with_target("interesting_target"),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     // Enables spans and events with targets starting with `interesting_target`:
diff --git a/tracing-subscriber/tests/layer_filters/filter_scopes.rs b/tracing-subscriber/tests/layer_filters/filter_scopes.rs
index d5608a8965..02d000748f 100644
--- a/tracing-subscriber/tests/layer_filters/filter_scopes.rs
+++ b/tracing-subscriber/tests/layer_filters/filter_scopes.rs
@@ -1,49 +1,49 @@
 use super::*;
-use tracing_mock::layer::MockLayer;
+use tracing_mock::{event, expect, layer::MockLayer};
 
 #[test]
 fn filters_span_scopes() {
     let (debug_layer, debug_handle) = layer::named("debug")
-        .enter(span::mock().at_level(Level::DEBUG))
-        .enter(span::mock().at_level(Level::INFO))
-        .enter(span::mock().at_level(Level::WARN))
-        .enter(span::mock().at_level(Level::ERROR))
+        .enter(expect::span().at_level(Level::DEBUG))
+        .enter(expect::span().at_level(Level::INFO))
+        .enter(expect::span().at_level(Level::WARN))
+        .enter(expect::span().at_level(Level::ERROR))
         .event(event::msg("hello world").in_scope(vec![
-            span::mock().at_level(Level::ERROR),
-            span::mock().at_level(Level::WARN),
-            span::mock().at_level(Level::INFO),
-            span::mock().at_level(Level::DEBUG),
+            expect::span().at_level(Level::ERROR),
+            expect::span().at_level(Level::WARN),
+            expect::span().at_level(Level::INFO),
+            expect::span().at_level(Level::DEBUG),
         ]))
-        .exit(span::mock().at_level(Level::ERROR))
-        .exit(span::mock().at_level(Level::WARN))
-        .exit(span::mock().at_level(Level::INFO))
-        .exit(span::mock().at_level(Level::DEBUG))
-        .done()
+        .exit(expect::span().at_level(Level::ERROR))
+        .exit(expect::span().at_level(Level::WARN))
+        .exit(expect::span().at_level(Level::INFO))
+        .exit(expect::span().at_level(Level::DEBUG))
+        .only()
         .run_with_handle();
     let (info_layer, info_handle) = layer::named("info")
-        .enter(span::mock().at_level(Level::INFO))
-        .enter(span::mock().at_level(Level::WARN))
-        .enter(span::mock().at_level(Level::ERROR))
+        .enter(expect::span().at_level(Level::INFO))
+        .enter(expect::span().at_level(Level::WARN))
+        .enter(expect::span().at_level(Level::ERROR))
         .event(event::msg("hello world").in_scope(vec![
-            span::mock().at_level(Level::ERROR),
-            span::mock().at_level(Level::WARN),
-            span::mock().at_level(Level::INFO),
+            expect::span().at_level(Level::ERROR),
+            expect::span().at_level(Level::WARN),
+            expect::span().at_level(Level::INFO),
         ]))
-        .exit(span::mock().at_level(Level::ERROR))
-        .exit(span::mock().at_level(Level::WARN))
-        .exit(span::mock().at_level(Level::INFO))
-        .done()
+        .exit(expect::span().at_level(Level::ERROR))
+        .exit(expect::span().at_level(Level::WARN))
+        .exit(expect::span().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let (warn_layer, warn_handle) = layer::named("warn")
-        .enter(span::mock().at_level(Level::WARN))
-        .enter(span::mock().at_level(Level::ERROR))
+        .enter(expect::span().at_level(Level::WARN))
+        .enter(expect::span().at_level(Level::ERROR))
         .event(event::msg("hello world").in_scope(vec![
-            span::mock().at_level(Level::ERROR),
-            span::mock().at_level(Level::WARN),
+            expect::span().at_level(Level::ERROR),
+            expect::span().at_level(Level::WARN),
         ]))
-        .exit(span::mock().at_level(Level::ERROR))
-        .exit(span::mock().at_level(Level::WARN))
-        .done()
+        .exit(expect::span().at_level(Level::ERROR))
+        .exit(expect::span().at_level(Level::WARN))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -70,38 +70,38 @@ fn filters_span_scopes() {
 fn filters_interleaved_span_scopes() {
     fn target_layer(target: &'static str) -> (MockLayer, subscriber::MockHandle) {
         layer::named(format!("target_{}", target))
-            .enter(span::mock().with_target(target))
-            .enter(span::mock().with_target(target))
+            .enter(expect::span().with_target(target))
+            .enter(expect::span().with_target(target))
             .event(event::msg("hello world").in_scope(vec![
-                span::mock().with_target(target),
-                span::mock().with_target(target),
+                expect::span().with_target(target),
+                expect::span().with_target(target),
             ]))
             .event(
                 event::msg("hello to my target")
                     .in_scope(vec![
-                        span::mock().with_target(target),
-                        span::mock().with_target(target),
+                        expect::span().with_target(target),
+                        expect::span().with_target(target),
                     ])
                     .with_target(target),
             )
-            .exit(span::mock().with_target(target))
-            .exit(span::mock().with_target(target))
-            .done()
+            .exit(expect::span().with_target(target))
+            .exit(expect::span().with_target(target))
+            .only()
             .run_with_handle()
     }
 
     let (a_layer, a_handle) = target_layer("a");
     let (b_layer, b_handle) = target_layer("b");
     let (all_layer, all_handle) = layer::named("all")
-        .enter(span::mock().with_target("b"))
-        .enter(span::mock().with_target("a"))
+        .enter(expect::span().with_target("b"))
+        .enter(expect::span().with_target("a"))
         .event(event::msg("hello world").in_scope(vec![
-            span::mock().with_target("a"),
-            span::mock().with_target("b"),
+            expect::span().with_target("a"),
+            expect::span().with_target("b"),
         ]))
-        .exit(span::mock().with_target("a"))
-        .exit(span::mock().with_target("b"))
-        .done()
+        .exit(expect::span().with_target("a"))
+        .exit(expect::span().with_target("b"))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
diff --git a/tracing-subscriber/tests/layer_filters/main.rs b/tracing-subscriber/tests/layer_filters/main.rs
index fed74038c7..80b929cbd6 100644
--- a/tracing-subscriber/tests/layer_filters/main.rs
+++ b/tracing-subscriber/tests/layer_filters/main.rs
@@ -2,33 +2,34 @@
 mod boxed;
 mod downcast_raw;
 mod filter_scopes;
+mod option;
 mod per_event;
 mod targets;
 mod trees;
 mod vec;
 
 use tracing::{level_filters::LevelFilter, Level};
-use tracing_mock::{event, layer, span, subscriber};
+use tracing_mock::{event, expect, layer, subscriber};
 use tracing_subscriber::{filter, prelude::*, Layer};
 
 #[test]
 fn basic_layer_filters() {
     let (trace_layer, trace_handle) = layer::named("trace")
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let (debug_layer, debug_handle) = layer::named("debug")
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let (info_layer, info_handle) = layer::named("info")
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -47,23 +48,23 @@ fn basic_layer_filters() {
 }
 
 #[test]
-fn basic_layer_filters_spans() {
+fn basic_layer_filter_spans() {
     let (trace_layer, trace_handle) = layer::named("trace")
-        .new_span(span::mock().at_level(Level::TRACE))
-        .new_span(span::mock().at_level(Level::DEBUG))
-        .new_span(span::mock().at_level(Level::INFO))
-        .done()
+        .new_span(expect::span().at_level(Level::TRACE))
+        .new_span(expect::span().at_level(Level::DEBUG))
+        .new_span(expect::span().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let (debug_layer, debug_handle) = layer::named("debug")
-        .new_span(span::mock().at_level(Level::DEBUG))
-        .new_span(span::mock().at_level(Level::INFO))
-        .done()
+        .new_span(expect::span().at_level(Level::DEBUG))
+        .new_span(expect::span().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let (info_layer, info_handle) = layer::named("info")
-        .new_span(span::mock().at_level(Level::INFO))
-        .done()
+        .new_span(expect::span().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -82,12 +83,12 @@ fn basic_layer_filters_spans() {
 }
 
 #[test]
-fn global_filters_layers_still_work() {
+fn global_filters_subscribers_still_work() {
     let (expect, handle) = layer::mock()
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -107,9 +108,9 @@ fn global_filters_layers_still_work() {
 #[test]
 fn global_filter_interests_are_cached() {
     let (expect, handle) = layer::mock()
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -133,12 +134,12 @@ fn global_filter_interests_are_cached() {
 }
 
 #[test]
-fn global_filters_affect_layer_filters() {
+fn global_filters_affect_subscriber_filters() {
     let (expect, handle) = layer::named("debug")
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
@@ -160,17 +161,17 @@ fn filter_fn() {
     let (all, all_handle) = layer::named("all_targets")
         .event(event::msg("hello foo"))
         .event(event::msg("hello bar"))
-        .done()
+        .only()
         .run_with_handle();
 
     let (foo, foo_handle) = layer::named("foo_target")
         .event(event::msg("hello foo"))
-        .done()
+        .only()
         .run_with_handle();
 
     let (bar, bar_handle) = layer::named("bar_target")
         .event(event::msg("hello bar"))
-        .done()
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
diff --git a/tracing-subscriber/tests/layer_filters/option.rs b/tracing-subscriber/tests/layer_filters/option.rs
new file mode 100644
index 0000000000..6eb4c40bb1
--- /dev/null
+++ b/tracing-subscriber/tests/layer_filters/option.rs
@@ -0,0 +1,143 @@
+use super::*;
+use tracing::Subscriber;
+use tracing_subscriber::{
+    filter::{self, LevelFilter},
+    prelude::*,
+    Layer,
+};
+
+fn filter_out_everything() -> filter::DynFilterFn {
+    // Use dynamic filter fn to disable interest caching and max-level hints,
+    // allowing us to put all of these tests in the same file.
+    filter::dynamic_filter_fn(|_, _| false)
+}
+
+#[test]
+fn option_some() {
+    let (layer, handle) = layer::mock().only().run_with_handle();
+    let layer = layer.with_filter(Some(filter_out_everything()));
+
+    let _guard = tracing_subscriber::registry().with(layer).set_default();
+
+    for i in 0..2 {
+        tracing::info!(i);
+    }
+
+    handle.assert_finished();
+}
+
+#[test]
+fn option_none() {
+    let (layer, handle) = layer::mock()
+        .event(expect::event())
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer = layer.with_filter(None::>);
+
+    let _guard = tracing_subscriber::registry().with(layer).set_default();
+
+    for i in 0..2 {
+        tracing::info!(i);
+    }
+
+    handle.assert_finished();
+}
+
+#[test]
+fn option_mixed() {
+    let (layer, handle) = layer::mock()
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer = layer
+        .with_filter(filter::dynamic_filter_fn(|meta, _ctx| {
+            meta.target() == "interesting"
+        }))
+        .with_filter(None::>);
+
+    let _guard = tracing_subscriber::registry().with(layer).set_default();
+
+    tracing::info!(target: "interesting", x="foo");
+    tracing::info!(target: "boring", x="bar");
+
+    handle.assert_finished();
+}
+
+/// The lack of a max level hint from a `None` filter should result in no max
+/// level hint when combined with other filters/layer.
+#[test]
+fn none_max_level_hint() {
+    let (layer_some, handle_none) = layer::mock()
+        .event(expect::event())
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let subscribe_none = layer_some.with_filter(None::>);
+    assert!(subscribe_none.max_level_hint().is_none());
+
+    let (layer_filter_fn, handle_filter_fn) = layer::mock()
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let max_level = Level::INFO;
+    let layer_filter_fn = layer_filter_fn.with_filter(
+        filter::dynamic_filter_fn(move |meta, _| return meta.level() <= &max_level)
+            .with_max_level_hint(max_level),
+    );
+    assert_eq!(layer_filter_fn.max_level_hint(), Some(LevelFilter::INFO));
+
+    let subscriber = tracing_subscriber::registry()
+        .with(subscribe_none)
+        .with(layer_filter_fn);
+    // The absence of a hint from the `None` filter upgrades the `INFO` hint
+    // from the filter fn layer.
+    assert!(subscriber.max_level_hint().is_none());
+
+    let _guard = subscriber.set_default();
+    tracing::info!(target: "interesting", x="foo");
+    tracing::debug!(target: "sometimes_interesting", x="bar");
+
+    handle_none.assert_finished();
+    handle_filter_fn.assert_finished();
+}
+
+/// The max level hint from inside a `Some(filter)` filter should be propagated
+/// and combined with other filters/layers.
+#[test]
+fn some_max_level_hint() {
+    let (layer_some, handle_some) = layer::mock()
+        .event(expect::event())
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer_some = layer_some.with_filter(Some(
+        filter::dynamic_filter_fn(move |meta, _| return meta.level() <= &Level::DEBUG)
+            .with_max_level_hint(Level::DEBUG),
+    ));
+    assert_eq!(layer_some.max_level_hint(), Some(LevelFilter::DEBUG));
+
+    let (layer_filter_fn, handle_filter_fn) = layer::mock()
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer_filter_fn = layer_filter_fn.with_filter(
+        filter::dynamic_filter_fn(move |meta, _| return meta.level() <= &Level::INFO)
+            .with_max_level_hint(Level::INFO),
+    );
+    assert_eq!(layer_filter_fn.max_level_hint(), Some(LevelFilter::INFO));
+
+    let subscriber = tracing_subscriber::registry()
+        .with(layer_some)
+        .with(layer_filter_fn);
+    // The `DEBUG` hint from the `Some` filter upgrades the `INFO` hint from the
+    // filter fn layer.
+    assert_eq!(subscriber.max_level_hint(), Some(LevelFilter::DEBUG));
+
+    let _guard = subscriber.set_default();
+    tracing::info!(target: "interesting", x="foo");
+    tracing::debug!(target: "sometimes_interesting", x="bar");
+
+    handle_some.assert_finished();
+    handle_filter_fn.assert_finished();
+}
diff --git a/tracing-subscriber/tests/layer_filters/per_event.rs b/tracing-subscriber/tests/layer_filters/per_event.rs
index 3a28d94f08..897c9f2df5 100644
--- a/tracing-subscriber/tests/layer_filters/per_event.rs
+++ b/tracing-subscriber/tests/layer_filters/per_event.rs
@@ -1,5 +1,5 @@
 use tracing::Level;
-use tracing_mock::{event, layer};
+use tracing_mock::{expect, layer};
 use tracing_subscriber::{field::Visit, layer::Filter, prelude::*};
 
 struct FilterEvent;
@@ -40,11 +40,11 @@ impl Filter for FilterEvent {
 }
 
 #[test]
-fn per_subscriber_event_field_filtering() {
+fn per_layer_event_field_filtering() {
     let (expect, handle) = layer::mock()
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let _subscriber = tracing_subscriber::registry()
diff --git a/tracing-subscriber/tests/layer_filters/targets.rs b/tracing-subscriber/tests/layer_filters/targets.rs
index c8133044b1..19bcff1489 100644
--- a/tracing-subscriber/tests/layer_filters/targets.rs
+++ b/tracing-subscriber/tests/layer_filters/targets.rs
@@ -1,4 +1,5 @@
 use super::*;
+use tracing_mock::event;
 use tracing_subscriber::{
     filter::{filter_fn, Targets},
     prelude::*,
@@ -39,7 +40,7 @@ fn inner_layer_short_circuits() {
 
     let (layer, handle) = layer::mock()
         .event(event::msg("hello world"))
-        .done()
+        .only()
         .run_with_handle();
 
     let filter = Targets::new().with_target("magic_target", LevelFilter::DEBUG);
diff --git a/tracing-subscriber/tests/layer_filters/trees.rs b/tracing-subscriber/tests/layer_filters/trees.rs
index 02830122ca..a0dbbbe907 100644
--- a/tracing-subscriber/tests/layer_filters/trees.rs
+++ b/tracing-subscriber/tests/layer_filters/trees.rs
@@ -1,37 +1,49 @@
 use super::*;
-use tracing_mock::layer::MockLayer;
+use tracing_mock::{event, expect, layer::MockLayer};
 
 #[test]
 fn basic_trees() {
     let (with_target, with_target_handle) = layer::named("info_with_target")
-        .event(event::mock().at_level(Level::INFO).with_target("my_target"))
-        .done()
+        .event(
+            expect::event()
+                .at_level(Level::INFO)
+                .with_target("my_target"),
+        )
+        .only()
         .run_with_handle();
 
     let (info, info_handle) = layer::named("info")
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::INFO)
                 .with_target(module_path!()),
         )
-        .event(event::mock().at_level(Level::INFO).with_target("my_target"))
-        .done()
+        .event(
+            expect::event()
+                .at_level(Level::INFO)
+                .with_target("my_target"),
+        )
+        .only()
         .run_with_handle();
 
     let (all, all_handle) = layer::named("all")
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::INFO)
                 .with_target(module_path!()),
         )
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::INFO).with_target("my_target"))
+        .event(expect::event().at_level(Level::TRACE))
+        .event(
+            expect::event()
+                .at_level(Level::INFO)
+                .with_target("my_target"),
+        )
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::TRACE)
                 .with_target("my_target"),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     let info_tree = info
@@ -57,41 +69,40 @@ fn basic_trees() {
 fn filter_span_scopes() {
     fn target_layer(target: &'static str) -> (MockLayer, subscriber::MockHandle) {
         layer::named(format!("target_{}", target))
-            .enter(span::mock().with_target(target).at_level(Level::INFO))
-            .event(
-                event::msg("hello world")
-                    .in_scope(vec![span::mock().with_target(target).at_level(Level::INFO)]),
-            )
-            .exit(span::mock().with_target(target).at_level(Level::INFO))
-            .done()
+            .enter(expect::span().with_target(target).at_level(Level::INFO))
+            .event(event::msg("hello world").in_scope(vec![
+                expect::span().with_target(target).at_level(Level::INFO),
+            ]))
+            .exit(expect::span().with_target(target).at_level(Level::INFO))
+            .only()
             .run_with_handle()
     }
 
     let (a_layer, a_handle) = target_layer("a");
     let (b_layer, b_handle) = target_layer("b");
     let (info_layer, info_handle) = layer::named("info")
-        .enter(span::mock().with_target("b").at_level(Level::INFO))
-        .enter(span::mock().with_target("a").at_level(Level::INFO))
+        .enter(expect::span().with_target("b").at_level(Level::INFO))
+        .enter(expect::span().with_target("a").at_level(Level::INFO))
         .event(event::msg("hello world").in_scope(vec![
-            span::mock().with_target("a").at_level(Level::INFO),
-            span::mock().with_target("b").at_level(Level::INFO),
+            expect::span().with_target("a").at_level(Level::INFO),
+            expect::span().with_target("b").at_level(Level::INFO),
         ]))
-        .exit(span::mock().with_target("a").at_level(Level::INFO))
-        .exit(span::mock().with_target("b").at_level(Level::INFO))
-        .done()
+        .exit(expect::span().with_target("a").at_level(Level::INFO))
+        .exit(expect::span().with_target("b").at_level(Level::INFO))
+        .only()
         .run_with_handle();
 
     let full_scope = vec![
-        span::mock().with_target("b").at_level(Level::TRACE),
-        span::mock().with_target("a").at_level(Level::INFO),
-        span::mock().with_target("b").at_level(Level::INFO),
-        span::mock().with_target("a").at_level(Level::TRACE),
+        expect::span().with_target("b").at_level(Level::TRACE),
+        expect::span().with_target("a").at_level(Level::INFO),
+        expect::span().with_target("b").at_level(Level::INFO),
+        expect::span().with_target("a").at_level(Level::TRACE),
     ];
     let (all_layer, all_handle) = layer::named("all")
-        .enter(span::mock().with_target("a").at_level(Level::TRACE))
-        .enter(span::mock().with_target("b").at_level(Level::INFO))
-        .enter(span::mock().with_target("a").at_level(Level::INFO))
-        .enter(span::mock().with_target("b").at_level(Level::TRACE))
+        .enter(expect::span().with_target("a").at_level(Level::TRACE))
+        .enter(expect::span().with_target("b").at_level(Level::INFO))
+        .enter(expect::span().with_target("a").at_level(Level::INFO))
+        .enter(expect::span().with_target("b").at_level(Level::TRACE))
         .event(event::msg("hello world").in_scope(full_scope.clone()))
         .event(
             event::msg("hello to my target")
@@ -103,11 +114,11 @@ fn filter_span_scopes() {
                 .with_target("b")
                 .in_scope(full_scope),
         )
-        .exit(span::mock().with_target("b").at_level(Level::TRACE))
-        .exit(span::mock().with_target("a").at_level(Level::INFO))
-        .exit(span::mock().with_target("b").at_level(Level::INFO))
-        .exit(span::mock().with_target("a").at_level(Level::TRACE))
-        .done()
+        .exit(expect::span().with_target("b").at_level(Level::TRACE))
+        .exit(expect::span().with_target("a").at_level(Level::INFO))
+        .exit(expect::span().with_target("b").at_level(Level::INFO))
+        .exit(expect::span().with_target("a").at_level(Level::TRACE))
+        .only()
         .run_with_handle();
 
     let a_layer = a_layer.with_filter(filter::filter_fn(|meta| {
diff --git a/tracing-subscriber/tests/layer_filters/vec.rs b/tracing-subscriber/tests/layer_filters/vec.rs
index dbe3674785..42aa308f6b 100644
--- a/tracing-subscriber/tests/layer_filters/vec.rs
+++ b/tracing-subscriber/tests/layer_filters/vec.rs
@@ -1,27 +1,27 @@
 use super::*;
 use tracing::Subscriber;
-use tracing_mock::layer::{self, MockLayer};
+use tracing_mock::{expect, layer::MockLayer};
 
 #[test]
 fn with_filters_unboxed() {
     let (trace_layer, trace_handle) = layer::named("trace")
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let trace_layer = trace_layer.with_filter(LevelFilter::TRACE);
 
     let (debug_layer, debug_handle) = layer::named("debug")
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let debug_layer = debug_layer.with_filter(LevelFilter::DEBUG);
 
     let (info_layer, info_handle) = layer::named("info")
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let info_layer = info_layer.with_filter(LevelFilter::INFO);
 
@@ -41,23 +41,23 @@ fn with_filters_unboxed() {
 #[test]
 fn with_filters_boxed() {
     let (unfiltered_layer, unfiltered_handle) = layer::named("unfiltered")
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let unfiltered_layer = unfiltered_layer.boxed();
 
     let (debug_layer, debug_handle) = layer::named("debug")
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let debug_layer = debug_layer.with_filter(LevelFilter::DEBUG).boxed();
 
     let (target_layer, target_handle) = layer::named("target")
-        .event(event::mock().at_level(Level::INFO))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .only()
         .run_with_handle();
     let target_layer = target_layer
         .with_filter(filter::filter_fn(|meta| meta.target() == "my_target"))
diff --git a/tracing-subscriber/tests/multiple_layer_filter_interests_cached.rs b/tracing-subscriber/tests/multiple_layer_filter_interests_cached.rs
index 13e1a94a3e..553c5371a2 100644
--- a/tracing-subscriber/tests/multiple_layer_filter_interests_cached.rs
+++ b/tracing-subscriber/tests/multiple_layer_filter_interests_cached.rs
@@ -4,7 +4,7 @@ use std::{
     sync::{Arc, Mutex},
 };
 use tracing::{Level, Subscriber};
-use tracing_mock::{event, layer};
+use tracing_mock::{expect, layer};
 use tracing_subscriber::{filter, prelude::*};
 
 #[test]
@@ -23,13 +23,13 @@ fn multiple_layer_filter_interests_are_cached() {
     let seen_info = seen_info2;
 
     let (info_layer, info_handle) = layer::named("info")
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let info_layer = info_layer.with_filter(filter);
 
@@ -47,11 +47,11 @@ fn multiple_layer_filter_interests_are_cached() {
     let seen_warn = seen_warn2;
 
     let (warn_layer, warn_handle) = layer::named("warn")
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let warn_layer = warn_layer.with_filter(filter);
 
diff --git a/tracing-subscriber/tests/option_filter_interest_caching.rs b/tracing-subscriber/tests/option_filter_interest_caching.rs
new file mode 100644
index 0000000000..609007cceb
--- /dev/null
+++ b/tracing-subscriber/tests/option_filter_interest_caching.rs
@@ -0,0 +1,53 @@
+// A separate test crate for `Option` for isolation from other tests
+// that may influence the interest cache.
+
+use std::sync::{
+    atomic::{AtomicUsize, Ordering},
+    Arc,
+};
+use tracing_mock::{expect, layer};
+use tracing_subscriber::{filter, prelude::*, Layer};
+
+/// A `None` filter should always be interested in events, and it should not
+/// needlessly degrade the caching of other filters.
+#[test]
+fn none_interest_cache() {
+    let (layer_none, handle_none) = layer::mock()
+        .event(expect::event())
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer_none = layer_none.with_filter(None::>);
+
+    let times_filtered = Arc::new(AtomicUsize::new(0));
+    let (layer_filter_fn, handle_filter_fn) = layer::mock()
+        .event(expect::event())
+        .event(expect::event())
+        .only()
+        .run_with_handle();
+    let layer_filter_fn = layer_filter_fn.with_filter(filter::filter_fn({
+        let times_filtered = Arc::clone(×_filtered);
+        move |_| {
+            times_filtered.fetch_add(1, Ordering::Relaxed);
+            true
+        }
+    }));
+
+    let subscriber = tracing_subscriber::registry()
+        .with(layer_none)
+        .with(layer_filter_fn);
+
+    let _guard = subscriber.set_default();
+    for _ in 0..2 {
+        tracing::debug!(target: "always_interesting", x="bar");
+    }
+
+    // The `None` filter is unchanging and performs no filtering, so it should
+    // be cacheable and always be interested in events. The filter fn is a
+    // non-dynamic filter fn, which means the result can be cached per callsite.
+    // The filter fn should only need to be called once, and the `Option` filter
+    // should not interfere in the caching of that result.
+    assert_eq!(times_filtered.load(Ordering::Relaxed), 1);
+    handle_none.assert_finished();
+    handle_filter_fn.assert_finished();
+}
diff --git a/tracing-subscriber/tests/same_len_filters.rs b/tracing-subscriber/tests/same_len_filters.rs
index 879e578d78..ac0b908d28 100644
--- a/tracing-subscriber/tests/same_len_filters.rs
+++ b/tracing-subscriber/tests/same_len_filters.rs
@@ -10,9 +10,9 @@ use tracing_subscriber::{filter::EnvFilter, prelude::*};
 fn same_length_targets() {
     let filter: EnvFilter = "foo=trace,bar=trace".parse().expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::TRACE))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::TRACE))
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
 
@@ -31,16 +31,16 @@ fn same_num_fields_event() {
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::TRACE)
-                .with_fields(field::mock("foo")),
+                .with_fields(expect::field("foo")),
         )
         .event(
-            event::mock()
+            expect::event()
                 .at_level(Level::TRACE)
-                .with_fields(field::mock("bar")),
+                .with_fields(expect::field("bar")),
         )
-        .done()
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
     with_default(subscriber, || {
@@ -58,18 +58,18 @@ fn same_num_fields_and_name_len() {
         .expect("filter should parse");
     let (subscriber, finished) = subscriber::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("bar")),
+                .with_field(expect::field("bar")),
         )
         .new_span(
-            span::mock()
+            expect::span()
                 .named("baz")
                 .at_level(Level::TRACE)
-                .with_field(field::mock("boz")),
+                .with_field(expect::field("boz")),
         )
-        .done()
+        .only()
         .run_with_handle();
     let subscriber = subscriber.with(filter);
     with_default(subscriber, || {
diff --git a/tracing-subscriber/tests/unhinted_layer_filters_dont_break_other_layers.rs b/tracing-subscriber/tests/unhinted_layer_filters_dont_break_other_layers.rs
index d8b38345f9..a0f3b51423 100644
--- a/tracing-subscriber/tests/unhinted_layer_filters_dont_break_other_layers.rs
+++ b/tracing-subscriber/tests/unhinted_layer_filters_dont_break_other_layers.rs
@@ -1,7 +1,7 @@
 #![cfg(feature = "registry")]
 use tracing::Level;
 use tracing_mock::{
-    event,
+    expect,
     layer::{self, MockLayer},
     subscriber,
 };
@@ -107,20 +107,20 @@ fn filter() -> DynFilterFn {
 
 fn unfiltered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::TRACE))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::TRACE))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
 
 fn filtered(name: &str) -> (MockLayer, subscriber::MockHandle) {
     layer::named(name)
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle()
 }
diff --git a/tracing-subscriber/tests/utils.rs b/tracing-subscriber/tests/utils.rs
index e95868d5ea..9a8eb30ace 100644
--- a/tracing-subscriber/tests/utils.rs
+++ b/tracing-subscriber/tests/utils.rs
@@ -7,11 +7,11 @@ use tracing_subscriber::prelude::*;
 fn init_ext_works() {
     let (subscriber, finished) = subscriber::mock()
         .event(
-            event::mock()
+            expect::event()
                 .at_level(tracing::Level::INFO)
                 .with_target("init_works"),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     let _guard = subscriber.set_default();
diff --git a/tracing-subscriber/tests/vec_subscriber_filter_interests_cached.rs b/tracing-subscriber/tests/vec_subscriber_filter_interests_cached.rs
index 1bfb4a0adf..e80cfa09cf 100644
--- a/tracing-subscriber/tests/vec_subscriber_filter_interests_cached.rs
+++ b/tracing-subscriber/tests/vec_subscriber_filter_interests_cached.rs
@@ -4,10 +4,7 @@ use std::{
     sync::{Arc, Mutex},
 };
 use tracing::{Level, Subscriber};
-use tracing_mock::{
-    event,
-    layer::{self, MockLayer},
-};
+use tracing_mock::{layer::MockLayer, *};
 use tracing_subscriber::{filter, prelude::*};
 
 #[test]
@@ -26,23 +23,23 @@ fn vec_layer_filter_interests_are_cached() {
 
     // This layer will return Interest::always for INFO and lower.
     let (info_layer, info_handle) = layer::named("info")
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let (info_layer, seen_info) = mk_filtered(Level::INFO, info_layer);
 
     // This layer will return Interest::always for WARN and lower.
     let (warn_layer, warn_handle) = layer::named("warn")
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let (warn_layer, seen_warn) = mk_filtered(Level::WARN, warn_layer);
 
diff --git a/tracing/README.md b/tracing/README.md
index 443e51458d..a42636f336 100644
--- a/tracing/README.md
+++ b/tracing/README.md
@@ -379,6 +379,7 @@ maintained by the `tokio` project. These include:
 - [`tracing-distributed`] Provides a generic implementation of a layer that reports traces spanning multiple machines to some backend.
 - [`tracing-actix`] provides `tracing` integration for the `actix` actor
   framework.
+- [`axum-insights`] provides `tracing` integration and Application insights export for the `axum` web framework.
 - [`tracing-gelf`] implements a subscriber for exporting traces in Greylog
   GELF format.
 - [`tracing-coz`] provides integration with the [coz] causal profiler
@@ -407,6 +408,7 @@ please let us know! We'd love to add your project to the list!
 [`tracing-distributed`]: https://crates.io/crates/tracing-distributed
 [honeycomb.io]: https://www.honeycomb.io/
 [`tracing-actix`]: https://crates.io/crates/tracing-actix
+[`axum-insights`]: https://crates.io/crates/axum-insights
 [`tracing-gelf`]: https://crates.io/crates/tracing-gelf
 [`tracing-coz`]: https://crates.io/crates/tracing-coz
 [coz]: https://github.com/plasma-umass/coz
diff --git a/tracing/src/lib.rs b/tracing/src/lib.rs
index 9bb8f46942..258cbe5906 100644
--- a/tracing/src/lib.rs
+++ b/tracing/src/lib.rs
@@ -214,7 +214,7 @@
 //! ### Configuring Attributes
 //!
 //! Both macros require a [`Level`] specifying the verbosity of the span or
-//! event. Optionally, the [target] and [parent span] may be overridden. If the
+//! event. Optionally, the, [target] and [parent span] may be overridden. If the
 //! target and parent span are not overridden, they will default to the
 //! module path where the macro was invoked and the current span (as determined
 //! by the subscriber), respectively.
@@ -237,7 +237,16 @@
 //! ```
 //!
 //! The span macros also take a string literal after the level, to set the name
-//! of the span.
+//! of the span (as above).  In the case of the event macros, the name of the event can
+//! be overridden (the default is `event file:line`) using the `name:` specifier.
+//!
+//! ```
+//! # use tracing::{span, event, Level};
+//! # fn main() {
+//! span!(Level::TRACE, "my span");
+//! event!(name: "some_info", Level::INFO, "something has happened!");
+//! # }
+//! ```
 //!
 //! ### Recording Fields
 //!
@@ -310,6 +319,19 @@
 //! # }
 //!```
 //!
+//! Constant expressions can also be used as field names. Constants
+//! must be enclosed in curly braces (`{}`) to indicate that the *value*
+//! of the constant is to be used as the field name, rather than the
+//! constant's name. For example:
+//! ```
+//! # use tracing::{span, Level};
+//! # fn main() {
+//! const RESOURCE_NAME: &str = "foo";
+//! // this span will have the field `foo = "some_id"`
+//! span!(Level::TRACE, "get", { RESOURCE_NAME } = "some_id");
+//! # }
+//!```
+//!
 //! The `?` sigil is shorthand that specifies a field should be recorded using
 //! its [`fmt::Debug`] implementation:
 //! ```
@@ -386,22 +408,6 @@
 //! span.record("parting", &"goodbye world!");
 //! ```
 //!
-//! Note that a span may have up to 32 fields. The following will not compile:
-//!
-//! ```rust,compile_fail
-//! # use tracing::Level;
-//! # fn main() {
-//! let bad_span = span!(
-//!     Level::TRACE,
-//!     "too many fields!",
-//!     a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9,
-//!     j = 10, k = 11, l = 12, m = 13, n = 14, o = 15, p = 16, q = 17,
-//!     r = 18, s = 19, t = 20, u = 21, v = 22, w = 23, x = 24, y = 25,
-//!     z = 26, aa = 27, bb = 28, cc = 29, dd = 30, ee = 31, ff = 32, gg = 33
-//! );
-//! # }
-//! ```
-//!
 //! Finally, events may also include human-readable messages, in the form of a
 //! [format string][fmt] and (optional) arguments, **after** the event's
 //! key-value fields. If a format string and arguments are provided,
@@ -719,6 +725,7 @@
 //!  - [`tracing-actix-web`] provides `tracing` integration for the `actix-web` web framework.
 //!  - [`tracing-actix`] provides `tracing` integration for the `actix` actor
 //!    framework.
+//!  - [`axum-insights`] provides `tracing` integration and Application insights export for the `axum` web framework.
 //!  - [`tracing-gelf`] implements a subscriber for exporting traces in Greylog
 //!    GELF format.
 //!  - [`tracing-coz`] provides integration with the [coz] causal profiler
@@ -747,6 +754,8 @@
 //!  - [`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.
 //!  - [`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`.
 //!
 //! 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!
@@ -758,6 +767,7 @@
 //! [honeycomb.io]: https://www.honeycomb.io/
 //! [`tracing-actix-web`]: https://crates.io/crates/tracing-actix-web
 //! [`tracing-actix`]: https://crates.io/crates/tracing-actix
+//! [`axum-insights`]: https://crates.io/crates/axum-insights
 //! [`tracing-gelf`]: https://crates.io/crates/tracing-gelf
 //! [`tracing-coz`]: https://crates.io/crates/tracing-coz
 //! [coz]: https://github.com/plasma-umass/coz
@@ -787,6 +797,8 @@
 //! [`tracing-logfmt`]: https://crates.io/crates/tracing-logfmt
 //! [`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing
 //! [`reqwest`]: https://crates.io/crates/reqwest
+//! [`tracing-cloudwatch`]: https://crates.io/crates/tracing-cloudwatch
+//! [`clippy-tracing`]: https://crates.io/crates/clippy-tracing
 //!
 //! 
 //!     Note: Some of these ecosystem crates are currently
diff --git a/tracing/src/macros.rs b/tracing/src/macros.rs
index a737348cbc..5aa2afe2e5 100644
--- a/tracing/src/macros.rs
+++ b/tracing/src/macros.rs
@@ -24,7 +24,7 @@ macro_rules! span {
     (target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
         {
             use $crate::__macro_support::Callsite as _;
-            static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+            static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
                 name: $name,
                 kind: $crate::metadata::Kind::SPAN,
                 target: $target,
@@ -33,10 +33,10 @@ macro_rules! span {
             };
             let mut interest = $crate::subscriber::Interest::never();
             if $crate::level_enabled!($lvl)
-                && { interest = CALLSITE.interest(); !interest.is_never() }
-                && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+                && { interest = __CALLSITE.interest(); !interest.is_never() }
+                && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
             {
-                let meta = CALLSITE.metadata();
+                let meta = __CALLSITE.metadata();
                 // span with explicit parent
                 $crate::Span::child_of(
                     $parent,
@@ -44,9 +44,9 @@ macro_rules! span {
                     &$crate::valueset!(meta.fields(), $($fields)*),
                 )
             } else {
-                let span = $crate::__macro_support::__disabled_span(CALLSITE.metadata());
+                let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata());
                 $crate::if_log_enabled! { $lvl, {
-                    span.record_all(&$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+                    span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
                 }};
                 span
             }
@@ -55,7 +55,7 @@ macro_rules! span {
     (target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
         {
             use $crate::__macro_support::Callsite as _;
-            static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+            static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
                 name: $name,
                 kind: $crate::metadata::Kind::SPAN,
                 target: $target,
@@ -64,19 +64,19 @@ macro_rules! span {
             };
             let mut interest = $crate::subscriber::Interest::never();
             if $crate::level_enabled!($lvl)
-                && { interest = CALLSITE.interest(); !interest.is_never() }
-                && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+                && { interest = __CALLSITE.interest(); !interest.is_never() }
+                && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
             {
-                let meta = CALLSITE.metadata();
+                let meta = __CALLSITE.metadata();
                 // span with contextual parent
                 $crate::Span::new(
                     meta,
                     &$crate::valueset!(meta.fields(), $($fields)*),
                 )
             } else {
-                let span = $crate::__macro_support::__disabled_span(CALLSITE.metadata());
+                let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata());
                 $crate::if_log_enabled! { $lvl, {
-                    span.record_all(&$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+                    span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
                 }};
                 span
             }
@@ -564,6 +564,7 @@ macro_rules! error_span {
 ///     "App warning: {}",
 ///     error
 /// );
+/// event!(name: "answer", Level::INFO, the_answer = data.0);
 /// event!(Level::INFO, the_answer = data.0);
 /// # }
 /// ```
@@ -582,9 +583,115 @@ macro_rules! error_span {
 // /// ```
 #[macro_export]
 macro_rules! event {
+    // Name / target / parent.
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::EVENT,
+            target: $target,
+            level: $lvl,
+            fields: $($fields)*
+        };
+
+        let enabled = $crate::level_enabled!($lvl) && {
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+        };
+        if enabled {
+            (|value_set: $crate::field::ValueSet| {
+                $crate::__tracing_log!(
+                    $lvl,
+                    __CALLSITE,
+                    &value_set
+                );
+                let meta = __CALLSITE.metadata();
+                // event with explicit parent
+                $crate::Event::child_of(
+                    $parent,
+                    meta,
+                    &value_set
+                );
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+        } else {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+            );
+        }
+    });
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+        $crate::event!(
+            name: $name,
+            target: $target,
+            parent: $parent,
+            $lvl,
+            { message = format_args!($($arg)+), $($fields)* }
+        )
+    );
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+    );
+    (name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($arg)+ })
+    );
+
+    // Name / target.
+    (name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::EVENT,
+            target: $target,
+            level: $lvl,
+            fields: $($fields)*
+        };
+        let enabled = $crate::level_enabled!($lvl) && {
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+        };
+        if enabled {
+            (|value_set: $crate::field::ValueSet| {
+                let meta = __CALLSITE.metadata();
+                // event with contextual parent
+                $crate::Event::dispatch(
+                    meta,
+                    &value_set
+                );
+                $crate::__tracing_log!(
+                    $lvl,
+                    __CALLSITE,
+                    &value_set
+                );
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+        } else {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+            );
+        }
+    });
+    (name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+        $crate::event!(
+            name: $name,
+            target: $target,
+            $lvl,
+            { message = format_args!($($arg)+), $($fields)* }
+        )
+    );
+    (name: $name:expr, target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+        $crate::event!(name: $name, target: $target, $lvl, { $($k).+ = $($fields)* })
+    );
+    (name: $name:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => (
+        $crate::event!(name: $name, target: $target, $lvl, { $($arg)+ })
+    );
+
+    // Target / parent.
     (target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
         use $crate::__macro_support::Callsite as _;
-        static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+        static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
             name: $crate::__macro_support::concat!(
                 "event ",
                 file!(),
@@ -598,33 +705,32 @@ macro_rules! event {
         };
 
         let enabled = $crate::level_enabled!($lvl) && {
-            let interest = CALLSITE.interest();
-            !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
         };
         if enabled {
             (|value_set: $crate::field::ValueSet| {
                 $crate::__tracing_log!(
                     $lvl,
-                    CALLSITE,
+                    __CALLSITE,
                     &value_set
                 );
-                let meta = CALLSITE.metadata();
+                let meta = __CALLSITE.metadata();
                 // event with explicit parent
                 $crate::Event::child_of(
                     $parent,
                     meta,
                     &value_set
                 );
-            })($crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
         } else {
             $crate::__tracing_log!(
                 $lvl,
-                CALLSITE,
-                &$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*)
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
             );
         }
     });
-
     (target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
         $crate::event!(
             target: $target,
@@ -639,9 +745,114 @@ macro_rules! event {
     (target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
         $crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ })
     );
+
+    // Name / parent.
+    (name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::EVENT,
+            target: module_path!(),
+            level: $lvl,
+            fields: $($fields)*
+        };
+
+        let enabled = $crate::level_enabled!($lvl) && {
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && __CALLSITE.is_enabled(interest)
+        };
+        if enabled {
+            (|value_set: $crate::field::ValueSet| {
+                $crate::__tracing_log!(
+                    $lvl,
+                    __CALLSITE,
+                    &value_set
+                );
+                let meta = __CALLSITE.metadata();
+                // event with explicit parent
+                $crate::Event::child_of(
+                    $parent,
+                    meta,
+                    &value_set
+                );
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+        } else {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+            );
+        }
+    });
+    (name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+        $crate::event!(
+            name: $name,
+            parent: $parent,
+            $lvl,
+            { message = format_args!($($arg)+), $($fields)* }
+        )
+    );
+    (name: $name:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+        $crate::event!(name: $name, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+    );
+    (name: $name:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+        $crate::event!(name: $name, parent: $parent, $lvl, { $($arg)+ })
+    );
+
+    // Name.
+    (name: $name:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::EVENT,
+            target: module_path!(),
+            level: $lvl,
+            fields: $($fields)*
+        };
+        let enabled = $crate::level_enabled!($lvl) && {
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+        };
+        if enabled {
+            (|value_set: $crate::field::ValueSet| {
+                let meta = __CALLSITE.metadata();
+                // event with contextual parent
+                $crate::Event::dispatch(
+                    meta,
+                    &value_set
+                );
+                $crate::__tracing_log!(
+                    $lvl,
+                    __CALLSITE,
+                    &value_set
+                );
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+        } else {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+            );
+        }
+    });
+    (name: $name:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+        $crate::event!(
+            name: $name,
+            $lvl,
+            { message = format_args!($($arg)+), $($fields)* }
+        )
+    );
+    (name: $name:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+        $crate::event!(name: $name, $lvl, { $($k).+ = $($fields)* })
+    );
+    (name: $name:expr, $lvl:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $lvl, { $($arg)+ })
+    );
+
+    // Target.
     (target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
         use $crate::__macro_support::Callsite as _;
-        static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+        static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
             name: $crate::__macro_support::concat!(
                 "event ",
                 file!(),
@@ -654,12 +865,12 @@ macro_rules! event {
             fields: $($fields)*
         };
         let enabled = $crate::level_enabled!($lvl) && {
-            let interest = CALLSITE.interest();
-            !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+            let interest = __CALLSITE.interest();
+            !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
         };
         if enabled {
             (|value_set: $crate::field::ValueSet| {
-                let meta = CALLSITE.metadata();
+                let meta = __CALLSITE.metadata();
                 // event with contextual parent
                 $crate::Event::dispatch(
                     meta,
@@ -667,15 +878,15 @@ macro_rules! event {
                 );
                 $crate::__tracing_log!(
                     $lvl,
-                    CALLSITE,
+                    __CALLSITE,
                     &value_set
                 );
-            })($crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+            })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
         } else {
             $crate::__tracing_log!(
                 $lvl,
-                CALLSITE,
-                &$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*)
+                __CALLSITE,
+                &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
             );
         }
     });
@@ -692,6 +903,8 @@ macro_rules! event {
     (target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, $lvl, { $($arg)+ })
     );
+
+    // Parent.
     (parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -751,6 +964,8 @@ macro_rules! event {
     (parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => (
         $crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ })
     );
+
+    // ...
     ( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -970,7 +1185,7 @@ macro_rules! enabled {
     (kind: $kind:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
         if $crate::level_enabled!($lvl) {
             use $crate::__macro_support::Callsite as _;
-            static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+            static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
                 name: $crate::__macro_support::concat!(
                     "enabled ",
                     file!(),
@@ -982,9 +1197,9 @@ macro_rules! enabled {
                 level: $lvl,
                 fields: $($fields)*
             };
-            let interest = CALLSITE.interest();
-            if !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest) {
-                let meta = CALLSITE.metadata();
+            let interest = __CALLSITE.interest();
+            if !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) {
+                let meta = __CALLSITE.metadata();
                 $crate::dispatcher::get_default(|current| current.enabled(meta))
             } else {
                 false
@@ -1081,10 +1296,46 @@ macro_rules! enabled {
 ///     if pos.x >= 0.0 { "positive" } else { "negative" },
 ///     if pos.y >= 0.0 { "positive" } else { "negative" }
 /// );
+/// trace!(name: "completed", position = ?pos);
 /// # }
 /// ```
 #[macro_export]
 macro_rules! trace {
+    // Name / target / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+    );
+
+    // Name / target.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+)
+    );
+
+    // Target / parent.
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
     );
@@ -1100,6 +1351,59 @@ macro_rules! trace {
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
     );
+
+    // Name / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+    );
+
+    // Name.
+    (name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+    );
+    (name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::TRACE, { $($k).+ $($field)* })
+    );
+    (name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+    );
+    (name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::TRACE, { %$($k).+ $($field)* })
+    );
+    (name: $name:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $crate::Level::TRACE, {}, $($arg)+)
+    );
+
+    // Target.
+    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+    );
+    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
+    );
+    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+    );
+    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
+    );
+    (target: $target:expr, $($arg:tt)+ ) => (
+        $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+)
+    );
+
+    // Parent.
     (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1166,21 +1470,8 @@ macro_rules! trace {
             $($arg)+
         )
     );
-    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
-    );
-    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
-    );
-    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
-    );
-    (target: $target:expr, $($arg:tt)+ ) => (
-        $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+)
-    );
+
+    // ...
     ({ $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1196,6 +1487,20 @@ macro_rules! trace {
             { $($k).+ = $($field)*}
         )
     );
+    (?$($k:ident).+ = $($field:tt)*) => (
+        $crate::event!(
+            target: module_path!(),
+            $crate::Level::TRACE,
+            { ?$($k).+ = $($field)*}
+        )
+    );
+    (%$($k:ident).+ = $($field:tt)*) => (
+        $crate::event!(
+            target: module_path!(),
+            $crate::Level::TRACE,
+            { %$($k).+ = $($field)*}
+        )
+    );
     ($($k:ident).+, $($field:tt)*) => (
         $crate::event!(
             target: module_path!(),
@@ -1268,10 +1573,46 @@ macro_rules! trace {
 ///
 /// debug!(?pos.x, ?pos.y);
 /// debug!(target: "app_events", position = ?pos, "New position");
+/// debug!(name: "completed", position = ?pos);
 /// # }
 /// ```
 #[macro_export]
 macro_rules! debug {
+    // Name / target / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+    );
+
+    // Name / target.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
+    );
+
+    // Target / parent.
     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
     );
@@ -1287,6 +1628,59 @@ macro_rules! debug {
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
     );
+
+    // Name / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+    );
+
+    // Name.
+    (name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+    );
+    (name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* })
+    );
+    (name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+    );
+    (name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+    );
+    (name: $name:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+)
+    );
+
+    // Target.
+    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+    );
+    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
+    );
+    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+    );
+    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+    );
+    (target: $target:expr, $($arg:tt)+ ) => (
+        $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
+    );
+
+    // Parent.
     (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1353,21 +1747,8 @@ macro_rules! debug {
             $($arg)+
         )
     );
-    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
-    );
-    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
-    );
-    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
-    );
-    (target: $target:expr, $($arg:tt)+ ) => (
-        $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
-    );
+
+    // ...
     ({ $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1480,11 +1861,47 @@ macro_rules! debug {
 ///     conn.port,
 ///     ?conn.speed,
 /// );
+/// info!(name: "completed", "completed connection to {:?}", addr);
 /// # }
 /// ```
 #[macro_export]
 macro_rules! info {
-     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    // Name / target / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+    );
+
+    // Name / target.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+)
+    );
+
+    // Target / parent.
+    (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)+ ) => (
@@ -1499,6 +1916,59 @@ macro_rules! info {
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
     );
+
+    // Name / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+    );
+
+    // Name.
+    (name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::INFO, { $($field)* }, $($arg)*)
+    );
+    (name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::INFO, { $($k).+ $($field)* })
+    );
+    (name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::INFO, { ?$($k).+ $($field)* })
+    );
+    (name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::INFO, { %$($k).+ $($field)* })
+    );
+    (name: $name:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $crate::Level::INFO, {}, $($arg)+)
+    );
+
+    // Target.
+    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
+    );
+    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
+    );
+    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
+    );
+    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::INFO, { %$($k).+ $($field)* })
+    );
+    (target: $target:expr, $($arg:tt)+ ) => (
+        $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+)
+    );
+
+    // Parent.
     (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1565,21 +2035,8 @@ macro_rules! info {
             $($arg)+
         )
     );
-    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
-    );
-    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
-    );
-    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, $($arg:tt)+ ) => (
-        $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+)
-    );
+
+    // ...
     ({ $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1685,11 +2142,47 @@ macro_rules! info {
 ///     warning = warn_description,
 ///     "Received warning for input: {:?}", input,
 /// );
+/// warn!(name: "invalid", ?input);
 /// # }
 /// ```
 #[macro_export]
 macro_rules! warn {
-     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    // Name / target / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+    );
+
+    // Name / target.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+)
+    );
+
+    // Target / parent.
+    (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)+ ) => (
@@ -1704,6 +2197,59 @@ macro_rules! warn {
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
     );
+
+    // Name / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+    );
+
+    // Name.
+    (name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::WARN, { $($field)* }, $($arg)*)
+    );
+    (name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::WARN, { $($k).+ $($field)* })
+    );
+    (name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::WARN, { ?$($k).+ $($field)* })
+    );
+    (name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::WARN, { %$($k).+ $($field)* })
+    );
+    (name: $name:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $crate::Level::WARN, {}, $($arg)+)
+    );
+
+    // Target.
+    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
+    );
+    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
+    );
+    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
+    );
+    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
+    );
+    (target: $target:expr, $($arg:tt)+ ) => (
+        $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+)
+    );
+
+    // Parent.
     (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1770,21 +2316,8 @@ macro_rules! warn {
             $($arg)+
         )
     );
-    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
-    );
-    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
-    );
-    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
-    );
-    (target: $target:expr, $($arg:tt)+ ) => (
-        $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+)
-    );
+
+    // ...
     ({ $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1886,11 +2419,47 @@ macro_rules! warn {
 /// error!(port, error = %err_info);
 /// error!(target: "app_events", "App Error: {}", err_info);
 /// error!({ info = err_info }, "error on port: {}", port);
+/// error!(name: "invalid_input", "Invalid input: {}", err_info);
 /// # }
 /// ```
 #[macro_export]
 macro_rules! error {
-     (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    // Name / target / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+    );
+
+    // Name / target.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+)
+    );
+
+    // Target / parent.
+    (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)+ ) => (
@@ -1905,6 +2474,59 @@ macro_rules! error {
     (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
         $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
     );
+
+    // Name / parent.
+    (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, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+    );
+
+    // Name.
+    (name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+    );
+    (name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::ERROR, { $($k).+ $($field)* })
+    );
+    (name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+    );
+    (name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(name: $name, $crate::Level::ERROR, { %$($k).+ $($field)* })
+    );
+    (name: $name:expr, $($arg:tt)+ ) => (
+        $crate::event!(name: $name, $crate::Level::ERROR, {}, $($arg)+)
+    );
+
+    // Target.
+    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+    );
+    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
+    );
+    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+    );
+    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+        $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
+    );
+    (target: $target:expr, $($arg:tt)+ ) => (
+        $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+)
+    );
+
+    // Parent.
     (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -1971,21 +2593,8 @@ macro_rules! error {
             $($arg)+
         )
     );
-    (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
-    );
-    (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
-    );
-    (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
-    );
-    (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
-        $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
-    );
-    (target: $target:expr, $($arg:tt)+ ) => (
-        $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+)
-    );
+
+    // ...
     ({ $($field:tt)+ }, $($arg:tt)+ ) => (
         $crate::event!(
             target: module_path!(),
@@ -2107,13 +2716,13 @@ macro_rules! callsite {
                 target: $target,
                 level: $lvl,
                 fields: $crate::fieldset!( $($fields)* ),
-                callsite: &CALLSITE,
+                callsite: &__CALLSITE,
                 kind: $kind,
             }
         };
-        static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META);
-        CALLSITE.register();
-        &CALLSITE
+        static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META);
+        __CALLSITE.register();
+        &__CALLSITE
     }};
 }
 
@@ -2157,7 +2766,7 @@ macro_rules! callsite2 {
                 target: $target,
                 level: $lvl,
                 fields: $crate::fieldset!( $($fields)* ),
-                callsite: &CALLSITE,
+                callsite: &__CALLSITE,
                 kind: $kind,
             }
         };
@@ -2193,79 +2802,79 @@ macro_rules! valueset {
     // };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$val) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$val) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$val as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$($k).+ as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$($k).+) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$($k).+) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$val) as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$val) as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$val as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$($k).+ as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$($k).+) as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$($k).+) as &dyn Value)) },
             $next,
         )
     };
@@ -2273,38 +2882,79 @@ macro_rules! valueset {
     // Handle literal names
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$val) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$val) as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$val as &dyn Value)) },
             $next,
             $($rest)*
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&debug(&$val) as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => {
         $crate::valueset!(
-            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&display(&$val) as &dyn Value)) },
             $next,
         )
     };
     (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, ::core::option::Option::Some(&$val as &dyn Value)) },
+            $next,
+        )
+    };
+
+    // Handle constant names
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr, $($rest:tt)*) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            $next,
+            $($rest)*
+        )
+    };
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr, $($rest:tt)*) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            $next,
+            $($rest)*
+        )
+    };
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr, $($rest:tt)*) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+            $next,
+            $($rest)*
+        )
+    };
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+            $next,
+        )
+    };
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr) => {
+        $crate::valueset!(
+            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+            $next,
+        )
+    };
+    (@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr) => {
         $crate::valueset!(
             @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
             $next,
@@ -2313,7 +2963,7 @@ macro_rules! valueset {
 
     // Remainder is unparsable, but exists --- must be format args!
     (@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => {
-        $crate::valueset!(@ { (&$next, Some(&format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
+        $crate::valueset!(@ { (&$next, ::core::option::Option::Some(&format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
     };
 
     // === entry ===
@@ -2324,7 +2974,7 @@ macro_rules! valueset {
             let mut iter = $fields.iter();
             $fields.value_set($crate::valueset!(
                 @ { },
-                iter.next().expect("FieldSet corrupted (this is a bug)"),
+                ::core::iter::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                 $($kvs)+
             ))
         }
@@ -2380,6 +3030,17 @@ macro_rules! fieldset {
         $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
     };
 
+    // Handle constant names
+    (@ { $(,)* $($out:expr),* } { $k:expr } = ?$val:expr, $($rest:tt)*) => {
+        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+    };
+    (@ { $(,)* $($out:expr),* } { $k:expr } = %$val:expr, $($rest:tt)*) => {
+        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+    };
+    (@ { $(,)* $($out:expr),* } { $k:expr } = $val:expr, $($rest:tt)*) => {
+        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+    };
+
     // Remainder is unparseable, but exists --- must be format args!
     (@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
         $crate::fieldset!(@ { "message", $($out),*, })
diff --git a/tracing/src/span.rs b/tracing/src/span.rs
index 579116ace5..3c235dc792 100644
--- a/tracing/src/span.rs
+++ b/tracing/src/span.rs
@@ -22,7 +22,7 @@
 //!   override their default values.
 //! - The span's [verbosity level]
 //! - A string literal providing the span's name.
-//! - Finally, between zero and 32 arbitrary key/value fields.
+//! - Finally, zero or more arbitrary key/value fields.
 //!
 //! [`target`]: super::Metadata::target
 //!
diff --git a/tracing/tests/enabled.rs b/tracing/tests/enabled.rs
index ea1c69804d..5a4596347e 100644
--- a/tracing/tests/enabled.rs
+++ b/tracing/tests/enabled.rs
@@ -13,7 +13,7 @@ fn level_and_target() {
                 meta.level() <= &Level::INFO
             }
         })
-        .done()
+        .only()
         .run();
 
     let _guard = tracing::subscriber::set_default(subscriber);
@@ -38,7 +38,7 @@ fn span_and_event() {
                 meta.level() <= &Level::INFO
             }
         })
-        .done()
+        .only()
         .run();
 
     let _guard = tracing::subscriber::set_default(subscriber);
diff --git a/tracing/tests/event.rs b/tracing/tests/event.rs
index 61df19ad3c..0be7c0bc56 100644
--- a/tracing/tests/event.rs
+++ b/tracing/tests/event.rs
@@ -22,17 +22,17 @@ macro_rules! event_without_message {
         fn $name() {
             let (subscriber, handle) = subscriber::mock()
                 .event(
-                    event::mock().with_fields(
-                        field::mock("answer")
+                    expect::event().with_fields(
+                        expect::field("answer")
                             .with_value(&42)
                             .and(
-                                field::mock("to_question")
+                                expect::field("to_question")
                                     .with_value(&"life, the universe, and everything"),
                             )
                             .only(),
                     ),
                 )
-                .done()
+                .only()
                 .run_with_handle();
 
             with_default(subscriber, || {
@@ -57,15 +57,19 @@ event_without_message! {nonzeroi32_event_without_message: std::num::NonZeroI32::
 #[test]
 fn event_with_message() {
     let (subscriber, handle) = subscriber::mock()
-        .event(event::msg(format_args!(
-            "hello from my event! yak shaved = {:?}",
-            true
-        )))
-        .done()
+        .event(
+            expect::event().with_fields(expect::field("message").with_value(
+                &tracing::field::debug(format_args!(
+                    "hello from my tracing::event! yak shaved = {:?}",
+                    true
+                )),
+            )),
+        )
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
-        debug!("hello from my event! yak shaved = {:?}", true);
+        debug!("hello from my tracing::event! yak shaved = {:?}", true);
     });
 
     handle.assert_finished();
@@ -76,10 +80,12 @@ fn event_with_message() {
 fn message_without_delims() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("answer")
+            expect::event().with_fields(
+                expect::field("answer")
                     .with_value(&42)
-                    .and(field::mock("question").with_value(&"life, the universe, and everything"))
+                    .and(
+                        expect::field("question").with_value(&"life, the universe, and everything"),
+                    )
                     .and(field::msg(format_args!(
                         "hello from my event! tricky? {:?}!",
                         true
@@ -87,7 +93,7 @@ fn message_without_delims() {
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -103,15 +109,17 @@ fn message_without_delims() {
 fn string_message_without_delims() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("answer")
+            expect::event().with_fields(
+                expect::field("answer")
                     .with_value(&42)
-                    .and(field::mock("question").with_value(&"life, the universe, and everything"))
+                    .and(
+                        expect::field("question").with_value(&"life, the universe, and everything"),
+                    )
                     .and(field::msg(format_args!("hello from my event")))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -127,23 +135,23 @@ fn string_message_without_delims() {
 fn one_with_everything() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock()
+            expect::event()
                 .with_fields(
-                    field::mock("message")
+                    expect::field("message")
                         .with_value(&tracing::field::debug(format_args!(
                             "{:#x} make me one with{what:.>20}",
                             4_277_009_102u64,
                             what = "everything"
                         )))
-                        .and(field::mock("foo").with_value(&666))
-                        .and(field::mock("bar").with_value(&false))
-                        .and(field::mock("like_a_butterfly").with_value(&42.0))
+                        .and(expect::field("foo").with_value(&666))
+                        .and(expect::field("bar").with_value(&false))
+                        .and(expect::field("like_a_butterfly").with_value(&42.0))
                         .only(),
                 )
                 .at_level(Level::ERROR)
                 .with_target("whatever"),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -163,13 +171,13 @@ fn one_with_everything() {
 fn moved_field() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("foo")
+            expect::event().with_fields(
+                expect::field("foo")
                     .with_value(&display("hello from my event"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let from = "my event";
@@ -184,14 +192,14 @@ fn moved_field() {
 fn dotted_field_name() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("foo.bar")
+            expect::event().with_fields(
+                expect::field("foo.bar")
                     .with_value(&true)
-                    .and(field::mock("foo.baz").with_value(&false))
+                    .and(expect::field("foo.baz").with_value(&false))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::event!(Level::INFO, foo.bar = true, foo.baz = false);
@@ -205,13 +213,13 @@ fn dotted_field_name() {
 fn borrowed_field() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("foo")
+            expect::event().with_fields(
+                expect::field("foo")
                     .with_value(&display("hello from my event"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let from = "my event";
@@ -242,15 +250,15 @@ fn move_field_out_of_struct() {
     };
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("x")
+            expect::event().with_fields(
+                expect::field("x")
                     .with_value(&debug(3.234))
-                    .and(field::mock("y").with_value(&debug(-1.223)))
+                    .and(expect::field("y").with_value(&debug(-1.223)))
                     .only(),
             ),
         )
-        .event(event::mock().with_fields(field::mock("position").with_value(&debug(&pos))))
-        .done()
+        .event(expect::event().with_fields(expect::field("position").with_value(&debug(&pos))))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -269,13 +277,13 @@ fn move_field_out_of_struct() {
 fn display_shorthand() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("my_field")
+            expect::event().with_fields(
+                expect::field("my_field")
                     .with_value(&display("hello world"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::event!(Level::TRACE, my_field = %"hello world");
@@ -289,13 +297,13 @@ fn display_shorthand() {
 fn debug_shorthand() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("my_field")
+            expect::event().with_fields(
+                expect::field("my_field")
                     .with_value(&debug("hello world"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::event!(Level::TRACE, my_field = ?"hello world");
@@ -309,14 +317,14 @@ fn debug_shorthand() {
 fn both_shorthands() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("display_field")
+            expect::event().with_fields(
+                expect::field("display_field")
                     .with_value(&display("hello world"))
-                    .and(field::mock("debug_field").with_value(&debug("hello world")))
+                    .and(expect::field("debug_field").with_value(&debug("hello world")))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::event!(Level::TRACE, display_field = %"hello world", debug_field = ?"hello world");
@@ -329,9 +337,9 @@ fn both_shorthands() {
 #[test]
 fn explicit_child() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -346,13 +354,13 @@ fn explicit_child() {
 #[test]
 fn explicit_child_at_levels() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .event(event::mock().with_explicit_parent(Some("foo")))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .event(expect::event().with_explicit_parent(Some("foo")))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -372,15 +380,15 @@ fn explicit_child_at_levels() {
 fn option_values() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("some_str")
+            expect::event().with_fields(
+                expect::field("some_str")
                     .with_value(&"yes")
-                    .and(field::mock("some_bool").with_value(&true))
-                    .and(field::mock("some_u64").with_value(&42_u64))
+                    .and(expect::field("some_bool").with_value(&true))
+                    .and(expect::field("some_u64").with_value(&42_u64))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -408,15 +416,15 @@ fn option_values() {
 fn option_ref_values() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("some_str")
+            expect::event().with_fields(
+                expect::field("some_str")
                     .with_value(&"yes")
-                    .and(field::mock("some_bool").with_value(&true))
-                    .and(field::mock("some_u64").with_value(&42_u64))
+                    .and(expect::field("some_bool").with_value(&true))
+                    .and(expect::field("some_u64").with_value(&42_u64))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -444,15 +452,15 @@ fn option_ref_values() {
 fn option_ref_mut_values() {
     let (subscriber, handle) = subscriber::mock()
         .event(
-            event::mock().with_fields(
-                field::mock("some_str")
+            expect::event().with_fields(
+                expect::field("some_str")
                     .with_value(&"yes")
-                    .and(field::mock("some_bool").with_value(&true))
-                    .and(field::mock("some_u64").with_value(&42_u64))
+                    .and(expect::field("some_bool").with_value(&true))
+                    .and(expect::field("some_u64").with_value(&42_u64))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -479,11 +487,15 @@ fn option_ref_mut_values() {
 #[test]
 fn string_field() {
     let (subscriber, handle) = subscriber::mock()
-        .event(event::mock().with_fields(field::mock("my_string").with_value(&"hello").only()))
+        .event(expect::event().with_fields(expect::field("my_string").with_value(&"hello").only()))
         .event(
-            event::mock().with_fields(field::mock("my_string").with_value(&"hello world!").only()),
+            expect::event().with_fields(
+                expect::field("my_string")
+                    .with_value(&"hello world!")
+                    .only(),
+            ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let mut my_string = String::from("hello");
@@ -498,3 +510,45 @@ fn string_field() {
 
     handle.assert_finished();
 }
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn constant_field_name() {
+    let expect_event = || {
+        expect::event().with_fields(
+            expect::field("foo")
+                .with_value(&"bar")
+                .and(expect::field("constant string").with_value(&"also works"))
+                .and(expect::field("foo.bar").with_value(&"baz"))
+                .and(expect::field("message").with_value(&debug(format_args!("quux"))))
+                .only(),
+        )
+    };
+    let (subscriber, handle) = subscriber::mock()
+        .event(expect_event())
+        .event(expect_event())
+        .only()
+        .run_with_handle();
+
+    with_default(subscriber, || {
+        const FOO: &str = "foo";
+        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"
+        );
+    });
+
+    handle.assert_finished();
+}
diff --git a/tracing/tests/filters_dont_leak.rs b/tracing/tests/filters_dont_leak.rs
index 2ef1c9c701..c46b91f18f 100644
--- a/tracing/tests/filters_dont_leak.rs
+++ b/tracing/tests/filters_dont_leak.rs
@@ -13,14 +13,14 @@ fn spans_dont_leak() {
     let (subscriber, handle) = subscriber::mock()
         .named("spans/subscriber1")
         .with_filter(|_| false)
-        .done()
+        .only()
         .run_with_handle();
 
     let _guard = tracing::subscriber::set_default(subscriber);
 
     do_span();
 
-    let alice = span::mock().named("alice");
+    let alice = expect::span().named("alice");
     let (subscriber2, handle2) = subscriber::mock()
         .named("spans/subscriber2")
         .with_filter(|_| true)
@@ -28,7 +28,7 @@ fn spans_dont_leak() {
         .enter(alice.clone())
         .exit(alice.clone())
         .drop_span(alice)
-        .done()
+        .only()
         .run_with_handle();
 
     tracing::subscriber::with_default(subscriber2, || {
@@ -53,7 +53,7 @@ fn events_dont_leak() {
     let (subscriber, handle) = subscriber::mock()
         .named("events/subscriber1")
         .with_filter(|_| false)
-        .done()
+        .only()
         .run_with_handle();
 
     let _guard = tracing::subscriber::set_default(subscriber);
@@ -63,8 +63,8 @@ fn events_dont_leak() {
     let (subscriber2, handle2) = subscriber::mock()
         .named("events/subscriber2")
         .with_filter(|_| true)
-        .event(event::mock())
-        .done()
+        .event(expect::event())
+        .only()
         .run_with_handle();
 
     tracing::subscriber::with_default(subscriber2, || {
diff --git a/tracing/tests/instrument.rs b/tracing/tests/instrument.rs
index a23769e66f..5247249946 100644
--- a/tracing/tests/instrument.rs
+++ b/tracing/tests/instrument.rs
@@ -33,17 +33,17 @@ fn span_on_drop() {
     }
 
     let subscriber = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock().at_level(Level::INFO))
-        .exit(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .enter(span::mock().named("bar"))
-        .event(event::mock().at_level(Level::INFO))
-        .exit(span::mock().named("bar"))
-        .drop_span(span::mock().named("bar"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event().at_level(Level::INFO))
+        .exit(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .enter(expect::span().named("bar"))
+        .event(expect::event().at_level(Level::INFO))
+        .exit(expect::span().named("bar"))
+        .drop_span(expect::span().named("bar"))
+        .only()
         .run();
 
     with_default(subscriber, || {
diff --git a/tracing/tests/macros.rs b/tracing/tests/macros.rs
index a9679a3e94..5c993ccffa 100644
--- a/tracing/tests/macros.rs
+++ b/tracing/tests/macros.rs
@@ -1,4 +1,14 @@
 #![deny(warnings)]
+// We call all macros in this module with `no_implicit_prelude` to ensure they do not depend on the standard prelude.
+#![no_implicit_prelude]
+extern crate tracing;
+#[cfg(target_arch = "wasm32")]
+extern crate wasm_bindgen_test;
+
+// TODO: remove this once https://github.com/tokio-rs/tracing/pull/2675#issuecomment-1667628907 is resolved
+#[cfg(target_arch = "wasm32")]
+use ::core::option::Option::None;
+
 use tracing::{
     callsite, debug, debug_span, enabled, error, error_span, event, event_enabled, info, info_span,
     span, span_enabled, trace, trace_span, warn, warn_span, Level,
@@ -111,80 +121,80 @@ fn error_span() {
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn span_root() {
-    span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
-    span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
-    span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 4,);
-    span!(target: "foo_events", parent: None, Level::TRACE, "foo");
-    span!(target: "foo_events", parent: None, Level::TRACE, "bar",);
-    span!(parent: None, Level::DEBUG, "foo", bar.baz = 2, quux = 3);
-    span!(parent: None, Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
-    span!(parent: None, Level::DEBUG, "foo");
-    span!(parent: None, Level::DEBUG, "bar",);
+    span!(target: "foo_events", parent: ::core::option::Option::None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
+    span!(target: "foo_events", parent: ::core::option::Option::None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
+    span!(target: "foo_events", parent: ::core::option::Option::None, Level::TRACE, "foo", bar.baz = 2, quux = 4,);
+    span!(target: "foo_events", parent: ::core::option::Option::None, Level::TRACE, "foo");
+    span!(target: "foo_events", parent: ::core::option::Option::None, Level::TRACE, "bar",);
+    span!(parent: ::core::option::Option::None, Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+    span!(parent: ::core::option::Option::None, Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+    span!(parent: ::core::option::Option::None, Level::DEBUG, "foo");
+    span!(parent: ::core::option::Option::None, Level::DEBUG, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn trace_span_root() {
-    trace_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
-    trace_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
-    trace_span!(target: "foo_events", parent: None, "foo");
-    trace_span!(target: "foo_events", parent: None, "bar",);
-    trace_span!(parent: None, "foo", bar.baz = 2, quux = 3);
-    trace_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
-    trace_span!(parent: None, "foo");
-    trace_span!(parent: None, "bar",);
+    trace_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    trace_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    trace_span!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    trace_span!(target: "foo_events", parent: ::core::option::Option::None, "bar",);
+    trace_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    trace_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    trace_span!(parent: ::core::option::Option::None, "foo");
+    trace_span!(parent: ::core::option::Option::None, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn debug_span_root() {
-    debug_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
-    debug_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
-    debug_span!(target: "foo_events", parent: None, "foo");
-    debug_span!(target: "foo_events", parent: None, "bar",);
-    debug_span!(parent: None, "foo", bar.baz = 2, quux = 3);
-    debug_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
-    debug_span!(parent: None, "foo");
-    debug_span!(parent: None, "bar",);
+    debug_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    debug_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    debug_span!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    debug_span!(target: "foo_events", parent: ::core::option::Option::None, "bar",);
+    debug_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    debug_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    debug_span!(parent: ::core::option::Option::None, "foo");
+    debug_span!(parent: ::core::option::Option::None, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn info_span_root() {
-    info_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
-    info_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
-    info_span!(target: "foo_events", parent: None, "foo");
-    info_span!(target: "foo_events", parent: None, "bar",);
-    info_span!(parent: None, "foo", bar.baz = 2, quux = 3);
-    info_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
-    info_span!(parent: None, "foo");
-    info_span!(parent: None, "bar",);
+    info_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    info_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    info_span!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    info_span!(target: "foo_events", parent: ::core::option::Option::None, "bar",);
+    info_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    info_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    info_span!(parent: ::core::option::Option::None, "foo");
+    info_span!(parent: ::core::option::Option::None, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn warn_span_root() {
-    warn_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
-    warn_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
-    warn_span!(target: "foo_events", parent: None, "foo");
-    warn_span!(target: "foo_events", parent: None, "bar",);
-    warn_span!(parent: None, "foo", bar.baz = 2, quux = 3);
-    warn_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
-    warn_span!(parent: None, "foo");
-    warn_span!(parent: None, "bar",);
+    warn_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    warn_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    warn_span!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    warn_span!(target: "foo_events", parent: ::core::option::Option::None, "bar",);
+    warn_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    warn_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    warn_span!(parent: ::core::option::Option::None, "foo");
+    warn_span!(parent: ::core::option::Option::None, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn error_span_root() {
-    error_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
-    error_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
-    error_span!(target: "foo_events", parent: None, "foo");
-    error_span!(target: "foo_events", parent: None, "bar",);
-    error_span!(parent: None, "foo", bar.baz = 2, quux = 3);
-    error_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
-    error_span!(parent: None, "foo");
-    error_span!(parent: None, "bar",);
+    error_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    error_span!(target: "foo_events", parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    error_span!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    error_span!(target: "foo_events", parent: ::core::option::Option::None, "bar",);
+    error_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 3);
+    error_span!(parent: ::core::option::Option::None, "foo", bar.baz = 2, quux = 4,);
+    error_span!(parent: ::core::option::Option::None, "foo");
+    error_span!(parent: ::core::option::Option::None, "bar",);
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -298,6 +308,48 @@ fn span_with_non_rust_symbol() {
     span!(Level::TRACE, "non-rust", "guid:x-request-id" = "abcdef");
 }
 
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn large_span() {
+    span!(
+        Level::TRACE,
+        "spans with more than 32 fields have been supported since #2508",
+        a = 1,
+        b = 2,
+        c = 3,
+        d = 4,
+        e = 5,
+        f = 6,
+        g = 7,
+        h = 8,
+        i = 9,
+        j = 10,
+        k = 11,
+        l = 12,
+        m = 13,
+        n = 14,
+        o = 15,
+        p = 16,
+        q = 17,
+        r = 18,
+        s = 19,
+        t = 20,
+        u = 21,
+        v = 22,
+        w = 23,
+        x = 24,
+        y = 25,
+        z = 26,
+        aa = 27,
+        bb = 28,
+        cc = 29,
+        dd = 30,
+        ee = 31,
+        ff = 32,
+        gg = 33
+    );
+}
+
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn event() {
@@ -399,6 +451,13 @@ fn locals_no_message() {
     let data = (42, "forty-two");
     let private_data = "private";
     let error = "a bad error";
+    event!(
+        name: "foo",
+        target: "app_events",
+        Level::WARN,
+        private_data,
+        ?data,
+    );
     event!(
         target: "app_events",
         Level::WARN,
@@ -438,6 +497,8 @@ fn trace() {
     trace!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     trace!({ foo = 2, bar.baz = 78 }, "quux");
     trace!({ foo = ?2, bar.baz = %78 }, "quux");
+    trace!(name: "foo", foo = 3, bar.baz = 2, quux = false);
+    trace!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     trace!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     trace!(target: "foo_events", foo = 3, bar.baz = 3,);
     trace!(target: "foo_events", "foo");
@@ -450,6 +511,12 @@ fn trace() {
     trace!(?foo);
     trace!(%foo);
     trace!(foo);
+    trace!(name: "foo", ?foo);
+    trace!(name: "foo", %foo);
+    trace!(name: "foo", foo);
+    trace!(name: "foo", ?foo, true, "message");
+    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);
@@ -474,6 +541,8 @@ fn debug() {
     debug!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     debug!({ foo = 2, bar.baz = 78 }, "quux");
     debug!({ foo = ?2, bar.baz = %78 }, "quux");
+    debug!(name: "foo", foo = 3, bar.baz = 2, quux = false);
+    debug!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     debug!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     debug!(target: "foo_events", foo = 3, bar.baz = 3,);
     debug!(target: "foo_events", "foo");
@@ -486,6 +555,12 @@ fn debug() {
     debug!(?foo);
     debug!(%foo);
     debug!(foo);
+    debug!(name: "foo", ?foo);
+    debug!(name: "foo", %foo);
+    debug!(name: "foo", foo);
+    debug!(name: "foo", ?foo, true, "message");
+    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);
@@ -510,6 +585,8 @@ fn info() {
     info!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     info!({ foo = 2, bar.baz = 78 }, "quux");
     info!({ foo = ?2, bar.baz = %78 }, "quux");
+    info!(name: "foo", foo = 3, bar.baz = 2, quux = false);
+    info!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     info!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     info!(target: "foo_events", foo = 3, bar.baz = 3,);
     info!(target: "foo_events", "foo");
@@ -522,6 +599,12 @@ fn info() {
     info!(?foo);
     info!(%foo);
     info!(foo);
+    info!(name: "foo", ?foo);
+    info!(name: "foo", %foo);
+    info!(name: "foo", foo);
+    info!(name: "foo", ?foo, true, "message");
+    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);
@@ -546,6 +629,8 @@ fn warn() {
     warn!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     warn!({ foo = 2, bar.baz = 78 }, "quux");
     warn!({ foo = ?2, bar.baz = %78 }, "quux");
+    warn!(name: "foo", foo = 3, bar.baz = 2, quux = false);
+    warn!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     warn!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     warn!(target: "foo_events", foo = 3, bar.baz = 3,);
     warn!(target: "foo_events", "foo");
@@ -558,6 +643,12 @@ fn warn() {
     warn!(?foo);
     warn!(%foo);
     warn!(foo);
+    warn!(name: "foo", ?foo);
+    warn!(name: "foo", %foo);
+    warn!(name: "foo", foo);
+    warn!(name: "foo", ?foo, true, "message");
+    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);
@@ -582,6 +673,8 @@ fn error() {
     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!(name: "foo", foo = 3, bar.baz = 2, quux = false);
+    error!(name: "foo", target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     error!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
     error!(target: "foo_events", foo = 3, bar.baz = 3,);
     error!(target: "foo_events", "foo");
@@ -594,6 +687,12 @@ fn error() {
     error!(?foo);
     error!(%foo);
     error!(foo);
+    error!(name: "foo", ?foo);
+    error!(name: "foo", %foo);
+    error!(name: "foo", foo);
+    error!(name: "foo", ?foo, true, "message");
+    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);
@@ -605,144 +704,192 @@ fn error() {
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn event_root() {
-    event!(parent: None, Level::DEBUG, foo = ?3, bar.baz = %2, quux = false);
+    event!(parent: ::core::option::Option::None, Level::DEBUG, foo = ?3, bar.baz = %2, quux = false);
     event!(
-        parent: None,
+        parent: ::core::option::Option::None,
         Level::DEBUG,
         foo = 3,
         bar.baz = 2,
         quux = false
     );
-    event!(parent: None, Level::DEBUG, foo = 3, bar.baz = 3,);
-    event!(parent: None, Level::DEBUG, "foo");
-    event!(parent: None, Level::DEBUG, "foo: {}", 3);
-    event!(parent: None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
-    event!(parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    event!(parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    event!(parent: None, Level::DEBUG, { foo = ?2, bar.baz = %78 }, "quux");
-    event!(target: "foo_events", parent: None, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
-    event!(target: "foo_events", parent: None, Level::DEBUG, foo = 3, bar.baz = 3,);
-    event!(target: "foo_events", parent: None, Level::DEBUG, "foo");
-    event!(target: "foo_events", parent: None, Level::DEBUG, "foo: {}", 3);
-    event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
-    event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+    event!(parent: ::core::option::Option::None, Level::DEBUG, foo = 3, bar.baz = 3,);
+    event!(parent: ::core::option::Option::None, Level::DEBUG, "foo");
+    event!(parent: ::core::option::Option::None, Level::DEBUG, "foo: {}", 3);
+    event!(parent: ::core::option::Option::None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+    event!(parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    event!(parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    event!(parent: ::core::option::Option::None, Level::DEBUG, { foo = ?2, bar.baz = %78 }, "quux");
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, foo = 3, bar.baz = 3,);
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, "foo");
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, "foo: {}", 3);
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    event!(target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, foo = 3, bar.baz = 3,);
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, "foo");
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, "foo: {}", 3);
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    event!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn trace_root() {
-    trace!(parent: None, foo = ?3, bar.baz = %2, quux = false);
-    trace!(parent: None, foo = 3, bar.baz = 2, quux = false);
-    trace!(parent: None, foo = 3, bar.baz = 3,);
-    trace!(parent: None, "foo");
-    trace!(parent: None, "foo: {}", 3);
-    trace!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    trace!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    trace!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    trace!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
-    trace!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
-    trace!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
-    trace!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
-    trace!(target: "foo_events", parent: None, "foo");
-    trace!(target: "foo_events", parent: None, "foo: {}", 3);
-    trace!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+    trace!(parent: ::core::option::Option::None, foo = ?3, bar.baz = %2, quux = false);
+    trace!(parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    trace!(parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    trace!(parent: ::core::option::Option::None, "foo");
+    trace!(parent: ::core::option::Option::None, "foo: {}", 3);
+    trace!(parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    trace!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    trace!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    trace!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 78 }, "quux");
+    trace!(parent: ::core::option::Option::None, { foo = ?2, bar.baz = %78 }, "quux");
+    trace!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    trace!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    trace!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    trace!(target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    trace!(target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    trace!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    trace!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    trace!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo");
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    trace!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn debug_root() {
-    debug!(parent: None, foo = ?3, bar.baz = %2, quux = false);
-    debug!(parent: None, foo = 3, bar.baz = 2, quux = false);
-    debug!(parent: None, foo = 3, bar.baz = 3,);
-    debug!(parent: None, "foo");
-    debug!(parent: None, "foo: {}", 3);
-    debug!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    debug!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    debug!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    debug!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
-    debug!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
-    debug!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
-    debug!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
-    debug!(target: "foo_events", parent: None, "foo");
-    debug!(target: "foo_events", parent: None, "foo: {}", 3);
-    debug!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+    debug!(parent: ::core::option::Option::None, foo = ?3, bar.baz = %2, quux = false);
+    debug!(parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    debug!(parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    debug!(parent: ::core::option::Option::None, "foo");
+    debug!(parent: ::core::option::Option::None, "foo: {}", 3);
+    debug!(parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    debug!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    debug!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    debug!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 78 }, "quux");
+    debug!(parent: ::core::option::Option::None, { foo = ?2, bar.baz = %78 }, "quux");
+    debug!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    debug!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    debug!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    debug!(target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    debug!(target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    debug!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    debug!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    debug!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo");
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    debug!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn info_root() {
-    info!(parent: None, foo = ?3, bar.baz = %2, quux = false);
-    info!(parent: None, foo = 3, bar.baz = 2, quux = false);
-    info!(parent: None, foo = 3, bar.baz = 3,);
-    info!(parent: None, "foo");
-    info!(parent: None, "foo: {}", 3);
-    info!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    info!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    info!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    info!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
-    info!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
-    info!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
-    info!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
-    info!(target: "foo_events", parent: None, "foo");
-    info!(target: "foo_events", parent: None, "foo: {}", 3);
-    info!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+    info!(parent: ::core::option::Option::None, foo = ?3, bar.baz = %2, quux = false);
+    info!(parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    info!(parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    info!(parent: ::core::option::Option::None, "foo");
+    info!(parent: ::core::option::Option::None, "foo: {}", 3);
+    info!(parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    info!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    info!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    info!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 78 }, "quux");
+    info!(parent: ::core::option::Option::None, { foo = ?2, bar.baz = %78 }, "quux");
+    info!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    info!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    info!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    info!(target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    info!(target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    info!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    info!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    info!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo");
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    info!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn warn_root() {
-    warn!(parent: None, foo = ?3, bar.baz = %2, quux = false);
-    warn!(parent: None, foo = 3, bar.baz = 2, quux = false);
-    warn!(parent: None, foo = 3, bar.baz = 3,);
-    warn!(parent: None, "foo");
-    warn!(parent: None, "foo: {}", 3);
-    warn!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    warn!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    warn!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    warn!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
-    warn!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
-    warn!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
-    warn!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
-    warn!(target: "foo_events", parent: None, "foo");
-    warn!(target: "foo_events", parent: None, "foo: {}", 3);
-    warn!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+    warn!(parent: ::core::option::Option::None, foo = ?3, bar.baz = %2, quux = false);
+    warn!(parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    warn!(parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    warn!(parent: ::core::option::Option::None, "foo");
+    warn!(parent: ::core::option::Option::None, "foo: {}", 3);
+    warn!(parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    warn!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    warn!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    warn!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 78 }, "quux");
+    warn!(parent: ::core::option::Option::None, { foo = ?2, bar.baz = %78 }, "quux");
+    warn!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    warn!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    warn!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    warn!(target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    warn!(target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    warn!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    warn!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    warn!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo");
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    warn!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn error_root() {
-    error!(parent: None, foo = ?3, bar.baz = %2, quux = false);
-    error!(parent: None, foo = 3, bar.baz = 2, quux = false);
-    error!(parent: None, foo = 3, bar.baz = 3,);
-    error!(parent: None, "foo");
-    error!(parent: None, "foo: {}", 3);
-    error!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    error!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    error!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    error!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
-    error!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
-    error!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
-    error!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
-    error!(target: "foo_events", parent: None, "foo");
-    error!(target: "foo_events", parent: None, "foo: {}", 3);
-    error!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
-    error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
-    error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
-    error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+    error!(parent: ::core::option::Option::None, foo = ?3, bar.baz = %2, quux = false);
+    error!(parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    error!(parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    error!(parent: ::core::option::Option::None, "foo");
+    error!(parent: ::core::option::Option::None, "foo: {}", 3);
+    error!(parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    error!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    error!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    error!(parent: ::core::option::Option::None, { foo = 2, bar.baz = 78 }, "quux");
+    error!(parent: ::core::option::Option::None, { foo = ?2, bar.baz = %78 }, "quux");
+    error!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    error!(target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    error!(target: "foo_events", parent: ::core::option::Option::None, "foo");
+    error!(target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    error!(target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    error!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    error!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    error!(target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 2, quux = false);
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, foo = 3, bar.baz = 3,);
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo");
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, "foo: {}", 3);
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 3, bar.baz = 80 }, "quux");
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    error!(name: "foo", target: "foo_events", parent: ::core::option::Option::None, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -766,6 +913,14 @@ fn event_with_parent() {
     event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, foo = 3, bar.baz = 3,);
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, "foo");
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, "foo: {}", 3);
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    event!(name: "foo", target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -790,6 +945,14 @@ fn trace_with_parent() {
     trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+    trace!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+    trace!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+    trace!(name: "foo", target: "foo_events", parent: &p, "foo");
+    trace!(name: "foo", target: "foo_events", parent: &p, "foo: {}", 3);
+    trace!(name: "foo", target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+    trace!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    trace!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    trace!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -814,6 +977,14 @@ fn debug_with_parent() {
     debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+    debug!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+    debug!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+    debug!(name: "foo", target: "foo_events", parent: &p, "foo");
+    debug!(name: "foo", target: "foo_events", parent: &p, "foo: {}", 3);
+    debug!(name: "foo", target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+    debug!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    debug!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    debug!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -838,6 +1009,14 @@ fn info_with_parent() {
     info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+    info!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+    info!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+    info!(name: "foo", target: "foo_events", parent: &p, "foo");
+    info!(name: "foo", target: "foo_events", parent: &p, "foo: {}", 3);
+    info!(name: "foo", target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+    info!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    info!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    info!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -862,6 +1041,14 @@ fn warn_with_parent() {
     warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+    warn!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+    warn!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+    warn!(name: "foo", target: "foo_events", parent: &p, "foo");
+    warn!(name: "foo", target: "foo_events", parent: &p, "foo: {}", 3);
+    warn!(name: "foo", target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+    warn!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    warn!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    warn!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -886,6 +1073,14 @@ fn error_with_parent() {
     error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
     error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
     error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+    error!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+    error!(name: "foo", target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+    error!(name: "foo", target: "foo_events", parent: &p, "foo");
+    error!(name: "foo", target: "foo_events", parent: &p, "foo: {}", 3);
+    error!(name: "foo", target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+    error!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+    error!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+    error!(name: "foo", target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
 }
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@@ -913,7 +1108,7 @@ fn field_shorthand_only() {
 #[test]
 fn borrow_val_events() {
     // Reproduces https://github.com/tokio-rs/tracing/issues/954
-    let mut foo = (String::new(), String::new());
+    let mut foo = (::std::string::String::new(), ::std::string::String::new());
     let zero = &mut foo.0;
     trace!(one = ?foo.1);
     debug!(one = ?foo.1);
@@ -927,7 +1122,7 @@ fn borrow_val_events() {
 #[test]
 fn borrow_val_spans() {
     // Reproduces https://github.com/tokio-rs/tracing/issues/954
-    let mut foo = (String::new(), String::new());
+    let mut foo = (::std::string::String::new(), ::std::string::String::new());
     let zero = &mut foo.0;
     let _span = trace_span!("span", one = ?foo.1);
     let _span = debug_span!("span", one = ?foo.1);
diff --git a/tracing/tests/macros_redefined_core.rs b/tracing/tests/macros_redefined_core.rs
deleted file mode 100644
index d830dcdb02..0000000000
--- a/tracing/tests/macros_redefined_core.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-extern crate self as core;
-
-use tracing::{enabled, event, span, Level};
-
-#[test]
-fn span() {
-    span!(Level::DEBUG, "foo");
-}
-
-#[test]
-fn event() {
-    event!(Level::DEBUG, "foo");
-}
-
-#[test]
-fn enabled() {
-    enabled!(Level::DEBUG);
-}
diff --git a/tracing/tests/max_level_hint.rs b/tracing/tests/max_level_hint.rs
index 63d3af6357..2e04bc3f1d 100644
--- a/tracing/tests/max_level_hint.rs
+++ b/tracing/tests/max_level_hint.rs
@@ -20,10 +20,10 @@ fn max_level_hints() {
             );
             true
         })
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     tracing::subscriber::set_global_default(subscriber).unwrap();
diff --git a/tracing/tests/multiple_max_level_hints.rs b/tracing/tests/multiple_max_level_hints.rs
index dd50a193b5..f78fda70fb 100644
--- a/tracing/tests/multiple_max_level_hints.rs
+++ b/tracing/tests/multiple_max_level_hints.rs
@@ -35,10 +35,10 @@ fn multiple_max_level_hints() {
             );
             level <= &Level::INFO
         })
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
     let (subscriber2, handle2) = subscriber::mock()
         .named("subscriber2")
@@ -51,11 +51,11 @@ fn multiple_max_level_hints() {
             );
             level <= &Level::DEBUG
         })
-        .event(event::mock().at_level(Level::INFO))
-        .event(event::mock().at_level(Level::DEBUG))
-        .event(event::mock().at_level(Level::WARN))
-        .event(event::mock().at_level(Level::ERROR))
-        .done()
+        .event(expect::event().at_level(Level::INFO))
+        .event(expect::event().at_level(Level::DEBUG))
+        .event(expect::event().at_level(Level::WARN))
+        .event(expect::event().at_level(Level::ERROR))
+        .only()
         .run_with_handle();
 
     let dispatch1 = tracing::Dispatch::new(subscriber1);
diff --git a/tracing/tests/no_subscriber.rs b/tracing/tests/no_subscriber.rs
index 5f927c1dee..d15a2c8a18 100644
--- a/tracing/tests/no_subscriber.rs
+++ b/tracing/tests/no_subscriber.rs
@@ -1,14 +1,15 @@
 #![cfg(feature = "std")]
 
-use tracing::subscriber::{self, NoSubscriber};
+use tracing_mock::subscriber;
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
 fn no_subscriber_disables_global() {
     // Reproduces https://github.com/tokio-rs/tracing/issues/1999
-    let (subscriber, handle) = tracing_mock::subscriber::mock().done().run_with_handle();
-    subscriber::set_global_default(subscriber).expect("setting global default must succeed");
-    subscriber::with_default(NoSubscriber::default(), || {
+    let (subscriber, handle) = subscriber::mock().only().run_with_handle();
+    tracing::subscriber::set_global_default(subscriber)
+        .expect("setting global default must succeed");
+    tracing::subscriber::with_default(tracing::subscriber::NoSubscriber::default(), || {
         tracing::info!("this should not be recorded");
     });
     handle.assert_finished();
diff --git a/tracing/tests/scoped_clobbers_default.rs b/tracing/tests/scoped_clobbers_default.rs
index 362d34a82c..dfd6fc9de2 100644
--- a/tracing/tests/scoped_clobbers_default.rs
+++ b/tracing/tests/scoped_clobbers_default.rs
@@ -8,12 +8,12 @@ fn scoped_clobbers_global() {
     let (scoped, scoped_handle) = subscriber::mock()
         .event(event::msg("before global"))
         .event(event::msg("before drop"))
-        .done()
+        .only()
         .run_with_handle();
 
     let (global, global_handle) = subscriber::mock()
         .event(event::msg("after drop"))
-        .done()
+        .only()
         .run_with_handle();
 
     // Set a scoped default subscriber, returning a guard.
diff --git a/tracing/tests/span.rs b/tracing/tests/span.rs
index e4e17757eb..09f1be8954 100644
--- a/tracing/tests/span.rs
+++ b/tracing/tests/span.rs
@@ -67,12 +67,12 @@ fn handles_to_different_spans_with_the_same_metadata_are_not_equal() {
 #[test]
 fn spans_always_go_to_the_subscriber_that_tagged_them() {
     let subscriber1 = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run();
     let subscriber2 = subscriber::mock().run();
 
@@ -94,12 +94,12 @@ fn spans_always_go_to_the_subscriber_that_tagged_them() {
 #[test]
 fn spans_always_go_to_the_subscriber_that_tagged_them_even_across_threads() {
     let subscriber1 = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run();
     let foo = with_default(subscriber1, || {
         let foo = tracing::span!(Level::TRACE, "foo");
@@ -122,10 +122,10 @@ fn spans_always_go_to_the_subscriber_that_tagged_them_even_across_threads() {
 #[test]
 fn dropping_a_span_calls_drop_span() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let span = tracing::span!(Level::TRACE, "foo");
@@ -140,11 +140,11 @@ fn dropping_a_span_calls_drop_span() {
 #[test]
 fn span_closes_after_event() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock())
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event())
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "foo").in_scope(|| {
@@ -159,14 +159,14 @@ fn span_closes_after_event() {
 #[test]
 fn new_span_after_event() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock())
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .enter(span::mock().named("bar"))
-        .exit(span::mock().named("bar"))
-        .drop_span(span::mock().named("bar"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event())
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .enter(expect::span().named("bar"))
+        .exit(expect::span().named("bar"))
+        .drop_span(expect::span().named("bar"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "foo").in_scope(|| {
@@ -182,11 +182,11 @@ fn new_span_after_event() {
 #[test]
 fn event_outside_of_span() {
     let (subscriber, handle) = subscriber::mock()
-        .event(event::mock())
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .event(expect::event())
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::debug!("my tracing::event!");
@@ -200,7 +200,7 @@ fn event_outside_of_span() {
 #[test]
 fn cloning_a_span_calls_clone_span() {
     let (subscriber, handle) = subscriber::mock()
-        .clone_span(span::mock().named("foo"))
+        .clone_span(expect::span().named("foo"))
         .run_with_handle();
     with_default(subscriber, || {
         let span = tracing::span!(Level::TRACE, "foo");
@@ -216,9 +216,9 @@ fn cloning_a_span_calls_clone_span() {
 #[test]
 fn drop_span_when_exiting_dispatchers_context() {
     let (subscriber, handle) = subscriber::mock()
-        .clone_span(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
+        .clone_span(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
         .run_with_handle();
     with_default(subscriber, || {
         let span = tracing::span!(Level::TRACE, "foo");
@@ -233,15 +233,15 @@ fn drop_span_when_exiting_dispatchers_context() {
 #[test]
 fn clone_and_drop_span_always_go_to_the_subscriber_that_tagged_the_span() {
     let (subscriber1, handle1) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .clone_span(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .clone_span(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
         .run_with_handle();
-    let subscriber2 = subscriber::mock().done().run();
+    let subscriber2 = subscriber::mock().only().run();
 
     let foo = with_default(subscriber1, || {
         let foo = tracing::span!(Level::TRACE, "foo");
@@ -264,10 +264,10 @@ fn clone_and_drop_span_always_go_to_the_subscriber_that_tagged_the_span() {
 #[test]
 fn span_closes_when_exited() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let foo = tracing::span!(Level::TRACE, "foo");
@@ -284,11 +284,11 @@ fn span_closes_when_exited() {
 #[test]
 fn enter() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock())
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event())
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let foo = tracing::span!(Level::TRACE, "foo");
@@ -303,11 +303,11 @@ fn enter() {
 #[test]
 fn entered() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock())
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event())
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let _span = tracing::span!(Level::TRACE, "foo").entered();
@@ -321,11 +321,11 @@ fn entered() {
 #[test]
 fn entered_api() {
     let (subscriber, handle) = subscriber::mock()
-        .enter(span::mock().named("foo"))
-        .event(event::mock())
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .event(expect::event())
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let span = tracing::span!(Level::TRACE, "foo").entered();
@@ -342,16 +342,16 @@ fn entered_api() {
 fn moved_field() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&display("hello from my span"))
                     .only(),
             ),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         let from = "my span";
@@ -371,11 +371,11 @@ fn moved_field() {
 fn dotted_field_name() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
-                .with_field(field::mock("fields.bar").with_value(&true).only()),
+                .with_field(expect::field("fields.bar").with_value(&true).only()),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "foo", fields.bar = true);
@@ -389,16 +389,16 @@ fn dotted_field_name() {
 fn borrowed_field() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&display("hello from my span"))
                     .only(),
             ),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -432,17 +432,17 @@ fn move_field_out_of_struct() {
     };
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("x")
+            expect::span().named("foo").with_field(
+                expect::field("x")
                     .with_value(&debug(3.234))
-                    .and(field::mock("y").with_value(&debug(-1.223)))
+                    .and(expect::field("y").with_value(&debug(-1.223)))
                     .only(),
             ),
         )
         .new_span(
-            span::mock()
+            expect::span()
                 .named("bar")
-                .with_field(field::mock("position").with_value(&debug(&pos)).only()),
+                .with_field(expect::field("position").with_value(&debug(&pos)).only()),
         )
         .run_with_handle();
 
@@ -465,10 +465,10 @@ fn move_field_out_of_struct() {
 fn float_values() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("x")
+            expect::span().named("foo").with_field(
+                expect::field("x")
                     .with_value(&3.234)
-                    .and(field::mock("y").with_value(&-1.223))
+                    .and(expect::field("y").with_value(&-1.223))
                     .only(),
             ),
         )
@@ -490,19 +490,19 @@ fn float_values() {
 fn add_field_after_new_span() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
-                .with_field(field::mock("bar").with_value(&5)
-                .and(field::mock("baz").with_value).only()),
+                .with_field(expect::field("bar").with_value(&5)
+                .and(expect::field("baz").with_value).only()),
         )
         .record(
-            span::mock().named("foo"),
-            field::mock("baz").with_value(&true).only(),
+            expect::span().named("foo"),
+            field::expect("baz").with_value(&true).only(),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -518,19 +518,19 @@ fn add_field_after_new_span() {
 #[test]
 fn add_fields_only_after_new_span() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
+        .new_span(expect::span().named("foo"))
         .record(
-            span::mock().named("foo"),
-            field::mock("bar").with_value(&5).only(),
+            expect::span().named("foo"),
+            field::expect("bar").with_value(&5).only(),
         )
         .record(
-            span::mock().named("foo"),
-            field::mock("baz").with_value(&true).only(),
+            expect::span().named("foo"),
+            field::expect("baz").with_value(&true).only(),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -549,21 +549,21 @@ fn add_fields_only_after_new_span() {
 fn record_new_value_for_field() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&5)
-                    .and(field::mock("baz").with_value(&false))
+                    .and(expect::field("baz").with_value(&false))
                     .only(),
             ),
         )
         .record(
-            span::mock().named("foo"),
-            field::mock("baz").with_value(&true).only(),
+            expect::span().named("foo"),
+            expect::field("baz").with_value(&true).only(),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -580,25 +580,25 @@ fn record_new_value_for_field() {
 fn record_new_values_for_fields() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&4)
-                    .and(field::mock("baz").with_value(&false))
+                    .and(expect::field("baz").with_value(&false))
                     .only(),
             ),
         )
         .record(
-            span::mock().named("foo"),
-            field::mock("bar").with_value(&5).only(),
+            expect::span().named("foo"),
+            expect::field("bar").with_value(&5).only(),
         )
         .record(
-            span::mock().named("foo"),
-            field::mock("baz").with_value(&true).only(),
+            expect::span().named("foo"),
+            expect::field("baz").with_value(&true).only(),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -616,12 +616,12 @@ fn record_new_values_for_fields() {
 fn new_span_with_target_and_log_level() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock()
+            expect::span()
                 .named("foo")
                 .with_target("app_span")
                 .at_level(Level::DEBUG),
         )
-        .done()
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -635,8 +635,8 @@ fn new_span_with_target_and_log_level() {
 #[test]
 fn explicit_root_span_is_root() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo").with_explicit_parent(None))
-        .done()
+        .new_span(expect::span().named("foo").with_explicit_parent(None))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -650,11 +650,11 @@ fn explicit_root_span_is_root() {
 #[test]
 fn explicit_root_span_is_root_regardless_of_ctx() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
-        .new_span(span::mock().named("bar").with_explicit_parent(None))
-        .exit(span::mock().named("foo"))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
+        .new_span(expect::span().named("bar").with_explicit_parent(None))
+        .exit(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -670,9 +670,13 @@ fn explicit_root_span_is_root_regardless_of_ctx() {
 #[test]
 fn explicit_child() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .new_span(span::mock().named("bar").with_explicit_parent(Some("foo")))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .new_span(
+            expect::span()
+                .named("bar")
+                .with_explicit_parent(Some("foo")),
+        )
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -687,13 +691,13 @@ fn explicit_child() {
 #[test]
 fn explicit_child_at_levels() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .new_span(span::mock().named("a").with_explicit_parent(Some("foo")))
-        .new_span(span::mock().named("b").with_explicit_parent(Some("foo")))
-        .new_span(span::mock().named("c").with_explicit_parent(Some("foo")))
-        .new_span(span::mock().named("d").with_explicit_parent(Some("foo")))
-        .new_span(span::mock().named("e").with_explicit_parent(Some("foo")))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .new_span(expect::span().named("a").with_explicit_parent(Some("foo")))
+        .new_span(expect::span().named("b").with_explicit_parent(Some("foo")))
+        .new_span(expect::span().named("c").with_explicit_parent(Some("foo")))
+        .new_span(expect::span().named("d").with_explicit_parent(Some("foo")))
+        .new_span(expect::span().named("e").with_explicit_parent(Some("foo")))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -712,12 +716,16 @@ fn explicit_child_at_levels() {
 #[test]
 fn explicit_child_regardless_of_ctx() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .new_span(span::mock().named("bar"))
-        .enter(span::mock().named("bar"))
-        .new_span(span::mock().named("baz").with_explicit_parent(Some("foo")))
-        .exit(span::mock().named("bar"))
-        .done()
+        .new_span(expect::span().named("foo"))
+        .new_span(expect::span().named("bar"))
+        .enter(expect::span().named("bar"))
+        .new_span(
+            expect::span()
+                .named("baz")
+                .with_explicit_parent(Some("foo")),
+        )
+        .exit(expect::span().named("bar"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -733,8 +741,8 @@ fn explicit_child_regardless_of_ctx() {
 #[test]
 fn contextual_root() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo").with_contextual_parent(None))
-        .done()
+        .new_span(expect::span().named("foo").with_contextual_parent(None))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -748,15 +756,15 @@ fn contextual_root() {
 #[test]
 fn contextual_child() {
     let (subscriber, handle) = subscriber::mock()
-        .new_span(span::mock().named("foo"))
-        .enter(span::mock().named("foo"))
+        .new_span(expect::span().named("foo"))
+        .enter(expect::span().named("foo"))
         .new_span(
-            span::mock()
+            expect::span()
                 .named("bar")
                 .with_contextual_parent(Some("foo")),
         )
-        .exit(span::mock().named("foo"))
-        .done()
+        .exit(expect::span().named("foo"))
+        .only()
         .run_with_handle();
 
     with_default(subscriber, || {
@@ -773,13 +781,13 @@ fn contextual_child() {
 fn display_shorthand() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("my_span").with_field(
-                field::mock("my_field")
+            expect::span().named("my_span").with_field(
+                expect::field("my_field")
                     .with_value(&display("hello world"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "my_span", my_field = %"hello world");
@@ -793,13 +801,13 @@ fn display_shorthand() {
 fn debug_shorthand() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("my_span").with_field(
-                field::mock("my_field")
+            expect::span().named("my_span").with_field(
+                expect::field("my_field")
                     .with_value(&debug("hello world"))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "my_span", my_field = ?"hello world");
@@ -813,14 +821,14 @@ fn debug_shorthand() {
 fn both_shorthands() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("my_span").with_field(
-                field::mock("display_field")
+            expect::span().named("my_span").with_field(
+                expect::field("display_field")
                     .with_value(&display("hello world"))
-                    .and(field::mock("debug_field").with_value(&debug("hello world")))
+                    .and(expect::field("debug_field").with_value(&debug("hello world")))
                     .only(),
             ),
         )
-        .done()
+        .only()
         .run_with_handle();
     with_default(subscriber, || {
         tracing::span!(Level::TRACE, "my_span", display_field = %"hello world", debug_field = ?"hello world");
@@ -828,3 +836,33 @@ fn both_shorthands() {
 
     handle.assert_finished();
 }
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn constant_field_name() {
+    let (subscriber, handle) = subscriber::mock()
+        .new_span(
+            expect::span().named("my_span").with_field(
+                expect::field("foo")
+                    .with_value(&"bar")
+                    .and(expect::field("constant string").with_value(&"also works"))
+                    .and(expect::field("foo.bar").with_value(&"baz"))
+                    .only(),
+            ),
+        )
+        .only()
+        .run_with_handle();
+
+    with_default(subscriber, || {
+        const FOO: &str = "foo";
+        tracing::span!(
+            Level::TRACE,
+            "my_span",
+            { std::convert::identity(FOO) } = "bar",
+            { "constant string" } = "also works",
+            foo.bar = "baz",
+        );
+    });
+
+    handle.assert_finished();
+}
diff --git a/tracing/tests/subscriber.rs b/tracing/tests/subscriber.rs
index 15557c107f..f676efeee8 100644
--- a/tracing/tests/subscriber.rs
+++ b/tracing/tests/subscriber.rs
@@ -11,8 +11,7 @@ use tracing::{
     subscriber::{with_default, Interest, Subscriber},
     Event, Level, Metadata,
 };
-
-use tracing_mock::*;
+use tracing_mock::{expect, subscriber};
 
 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
 #[test]
@@ -61,16 +60,16 @@ fn event_macros_dont_infinite_loop() {
 fn boxed_subscriber() {
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&display("hello from my span"))
                     .only(),
             ),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
-        .done()
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
+        .only()
         .run_with_handle();
     let subscriber: Box = Box::new(subscriber);
 
@@ -94,20 +93,20 @@ fn arced_subscriber() {
 
     let (subscriber, handle) = subscriber::mock()
         .new_span(
-            span::mock().named("foo").with_field(
-                field::mock("bar")
+            expect::span().named("foo").with_field(
+                expect::field("bar")
                     .with_value(&display("hello from my span"))
                     .only(),
             ),
         )
-        .enter(span::mock().named("foo"))
-        .exit(span::mock().named("foo"))
-        .drop_span(span::mock().named("foo"))
+        .enter(expect::span().named("foo"))
+        .exit(expect::span().named("foo"))
+        .drop_span(expect::span().named("foo"))
         .event(
-            event::mock()
-                .with_fields(field::mock("message").with_value(&display("hello from my event"))),
+            expect::event()
+                .with_fields(expect::field("message").with_value(&display("hello from my event"))),
         )
-        .done()
+        .only()
         .run_with_handle();
     let subscriber: Arc = Arc::new(subscriber);