trace: Add shorthand for field::display and field::debug (#1088)

## Motivation

In `tokio-trace`, field values may be recorded as either a subset of
Rust primitive types or as `fmt::Display` and `fmt::Debug`
implementations. Currently, `tokio-trace` provides the `field::display`
and `field::debug` functions which wrap a type with a type that
implements `Value` using the wrapped type's `fmt::Display` or
`fmt::Debug` implementation. However, importing and using these
functions adds unnecessary boilerplate. 

In #1081, @jonhoo suggested adding shorthand syntax to the macros,
similar to that used by the `slog` crate, as a solution for the
wordiness of the current API.

## Solution

This branch adds `?` and `%` sigils to field values in the span and
event macros, which expand to the `field::debug` and `field::display`
wrappers, respectively. The shorthand sigils may be used in any position
where the macros take a field value.

For example:
```rust
trace_span!("foo", my_field = ?something, ...); // shorthand for `debug`
info!(foo = %value, bar = false, ...) // shorthand for `display`
```

Adding this shorthand required a fairly large change to how field
key-value pairs are handled by the macros --- since `%foo` and `%foo`
are not valid Rust expressions, we can no longer match repeated 
`$ident = $expr` patterns, and must now match field lists as repeated
token trees. The inner helper macros for constructing `FieldSet`s and
`ValueSet`s have to parse the token trees recursively. This added a
decent chunk of complexity, but fortunately we have a large number of
compile tests for the macros and I'm quite confident that all existing
invocations will still work.

Closes #1081

Signed-off-by: Eliza Weisman <[email protected]>
This commit is contained in:
Eliza Weisman
2019-05-21 10:31:48 -07:00
committed by GitHub
parent 38092010c4
commit b2c53987d9
5 changed files with 604 additions and 462 deletions
+40 -3
View File
@@ -94,6 +94,40 @@
//! # }
//!```
//!
//! The [`field::display`] and [`field::debug`] functions are used to record
//! fields on spans or events using their `fmt::Display` and `fmt::Debug`
//! implementations (rather than as typed data). This may be used in lieu of
//! custom `Value` implementations for complex or user-defined types.
//!
//! In addition, the span and event macros permit the use of the `%` and `?`
//! sigils as shorthand for `field::display` and `field::debug`, respectively.
//! For example:
//!
//! ```
//! # #[macro_use]
//! # extern crate tokio_trace;
//! # use tokio_trace::Level;
//! # fn main() {
//! #[derive(Debug)]
//! struct MyStruct {
//! my_field: &'static str,
//! }
//!
//! let my_struct = MyStruct {
//! my_field: "Hello world!"
//! };
//!
//! let my_span = span!(
//! Level::TRACE,
//! "my_span",
//! // `my_struct` will be recorded using its `fmt::Debug` implementation.
//! my_struct = ?my_struct,
//! // `my_field` will be recorded using the implementation of `fmt::Display` for `&str`.
//! my_struct.my_field = %my_struct.my_field,
//! );
//! # }
//!```
//!
//! ### When to use spans
//!
//! As a rule of thumb, spans should be used to represent discrete units of work
@@ -254,7 +288,8 @@
//! ```rust
//! #[macro_use]
//! extern crate tokio_trace;
//! use tokio_trace::{field, Level};
//! use tokio_trace::Level;
//!
//! # #[derive(Debug)] pub struct Yak(String);
//! # impl Yak { fn shave(&mut self, _: u32) {} }
//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }
@@ -262,7 +297,7 @@
//! pub fn shave_the_yak(yak: &mut Yak) {
//! // Create a new span for this invocation of `shave_the_yak`, annotated
//! // with the yak being shaved as a *field* on the span.
//! span!(Level::TRACE, "shave_the_yak", yak = field::debug(&yak)).enter(|| {
//! span!(Level::TRACE, "shave_the_yak", yak = ?yak).enter(|| {
//! // Since the span is annotated with the yak, it is part of the context
//! // for everything happening inside the span. Therefore, we don't need
//! // to add it to the message for this event, as the `log` crate does.
@@ -274,7 +309,7 @@
//! // We can add the razor as a field rather than formatting it
//! // as part of the message, allowing subscribers to consume it
//! // in a more structured manner:
//! info!({ razor = field::display(razor) }, "Razor located");
//! info!({ razor = %razor }, "Razor located");
//! yak.shave(razor);
//! break;
//! }
@@ -387,6 +422,8 @@
//! [`exit`]: subscriber/trait.Subscriber.html#tymethod.exit
//! [`enabled`]: subscriber/trait.Subscriber.html#tymethod.enabled
//! [metadata]: struct.Metadata.html
//! [`field::display`]: field/fn.display.html
//! [`field::debug`]: field/fn.debug.html
//! [`tokio-trace-nursery`]: https://github.com/tokio-rs/tokio-trace-nursery
//! [`tokio-trace-futures`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-futures
//! [`tokio-trace-fmt`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-fmt
+404 -451
View File
File diff suppressed because it is too large Load Diff