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
+63 -1
View File
@@ -4,7 +4,11 @@ mod support;
use self::support::*;
use std::thread;
use tokio_trace::{field::display, subscriber::with_default, Level, Span};
use tokio_trace::{
field::{debug, display},
subscriber::with_default,
Level, Span,
};
#[test]
fn handles_to_the_same_span_are_equal() {
@@ -547,3 +551,61 @@ fn contextual_child() {
handle.assert_finished();
}
#[test]
fn display_shorthand() {
let (subscriber, handle) = subscriber::mock()
.new_span(
span::mock().named("my_span").with_field(
field::mock("my_field")
.with_value(&display("hello world"))
.only(),
),
)
.done()
.run_with_handle();
with_default(subscriber, || {
span!(Level::TRACE, "my_span", my_field = %"hello world");
});
handle.assert_finished();
}
#[test]
fn debug_shorthand() {
let (subscriber, handle) = subscriber::mock()
.new_span(
span::mock().named("my_span").with_field(
field::mock("my_field")
.with_value(&debug("hello world"))
.only(),
),
)
.done()
.run_with_handle();
with_default(subscriber, || {
span!(Level::TRACE, "my_span", my_field = ?"hello world");
});
handle.assert_finished();
}
#[test]
fn both_shorthands() {
let (subscriber, handle) = subscriber::mock()
.new_span(
span::mock().named("my_span").with_field(
field::mock("display_field")
.with_value(&display("hello world"))
.and(field::mock("debug_field").with_value(&debug("hello world")))
.only(),
),
)
.done()
.run_with_handle();
with_default(subscriber, || {
span!(Level::TRACE, "my_span", display_field = %"hello world", debug_field = ?"hello world");
});
handle.assert_finished();
}