Skip to content

Commit

Permalink
core: add field::Empty
Browse files Browse the repository at this point in the history
Right now, there is no way to indicate that a span field _currently_
has no value but that a value will be recorded later. Tracing used to
support this concept, but when we added local-variable shorthand, it was
removed from the macros, as we needed to use the previous syntax for
indicating empty fields for local variable shorthand. See #77 for
details.

This commit side-steps the problem of determining an appropriate
_syntax_ for empty fields by adding a special value _type_, called
`Empty`. Now, empty values can be indicated like
```rust
span!("my_span", foo = 5, bar = tracing::field::Empty);
```
The `Empty` type implements `Value`, but its' `record` method is a no-op
that doesn't' call any functions on the visitor. Therefore, when a field
is empty, the visitor will not see it. An empty field can then be
recorded later using `Subscriber::record` (or the corresponding `Span`
method in `tracing`).

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw committed Jan 27, 2020
1 parent 9810893 commit a327821
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tracing-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name = "tracing-core"
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.9"
version = "0.1.10"
authors = ["Tokio Contributors <team@tokio.rs>"]
license = "MIT"
readme = "README.md"
Expand Down
34 changes: 34 additions & 0 deletions tracing-core/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ pub struct Field {
fields: FieldSet,
}

/// An empty field.
///
/// This can be used to indicate that the value of a field is not currently
/// present but will be recorded later.
///
/// When a field's value is `Empty`. it will not be recorded.
#[derive(Debug, Eq, PartialEq)]
pub struct Empty;

/// Describes the fields present on a span.
pub struct FieldSet {
/// The names of each field on the described span.
Expand Down Expand Up @@ -456,6 +465,12 @@ impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
}
}

impl crate::sealed::Sealed for Empty {}
impl Value for Empty {
#[inline]
fn record(&self, _: &Field, _: &mut dyn Visit) {}
}

// ===== impl Field =====

impl Field {
Expand Down Expand Up @@ -865,6 +880,25 @@ mod test {
valueset.record(&mut MyVisitor);
}

#[test]
fn empty_fields_are_skipped() {
let fields = TEST_META_1.fields();
let values = &[
(&fields.field("foo").unwrap(), Some(&Empty as &dyn Value)),
(&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
(&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
];

struct MyVisitor;
impl Visit for MyVisitor {
fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
assert_eq!(field.name(), "bar")
}
}
let valueset = fields.value_set(values);
valueset.record(&mut MyVisitor);
}

#[test]
fn record_debug_fn() {
let fields = TEST_META_1.fields();
Expand Down

0 comments on commit a327821

Please sign in to comment.