Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: document valuable support #1887

Merged
merged 12 commits into from
Feb 3, 2022
4 changes: 1 addition & 3 deletions examples/examples/valuable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
//!
//! Therefore, when `valuable` support is not enabled, this example falls back to using
//! `fmt::Debug` to record fields that implement `valuable::Valuable`.
#[cfg(tracing_unstable)]
use tracing::field::valuable;
use tracing::{info, info_span};
use valuable::Valuable;

Expand Down Expand Up @@ -49,7 +47,7 @@ fn main() {
// If the `valuable` feature is enabled, record `user` using its'
// `valuable::Valuable` implementation:
#[cfg(tracing_unstable)]
let span = info_span!("Processing", user = valuable(&user));
let span = info_span!("Processing", user = user.as_value());

// Otherwise, record `user` using its `fmt::Debug` implementation:
#[cfg(not(tracing_unstable))]
Expand Down
4 changes: 3 additions & 1 deletion netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
[build.environment]
RUSTDOCFLAGS="""
-D warnings \
--cfg docsrs
--cfg docsrs \
--cfg tracing_unstable
"""
RUSTFLAGS="--cfg tracing_unstable"

[[redirects]]
from = "/"
Expand Down
8 changes: 6 additions & 2 deletions 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.21"
version = "0.1.22"
authors = ["Tokio Contributors <team@tokio.rs>"]
license = "MIT"
readme = "README.md"
Expand Down Expand Up @@ -41,4 +41,8 @@ valuable = { version = "0.1.0", optional = true, default_features = false }

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
# enable unstable features in the documentation
rustdoc-args = ["--cfg", "docsrs", "--cfg", "tracing_unstable"]
# it's necessary to _also_ pass `--cfg tracing_unstable` to rustc, or else
# dependencies will not be enabled, and the docs build will fail.
rustc-args = ["--cfg", "tracing_unstable"]
108 changes: 88 additions & 20 deletions tracing-core/src/field.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Span and `Event` key-value data.
//! `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
Expand All @@ -24,8 +24,81 @@
//! recorded as typed data by calling the [`Value::record`] method on these
//! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
//! represents the behavior used to record values of various types. For example,
//! we might record integers by incrementing counters for their field names,
//! rather than printing them.
//! an implementation of `Visit` might record integers by incrementing counters
//! for their field names rather than printing them.
//!
//!
//! # Using `valuable`
//!
//! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
//! number of Rust primitives as typed values, and only permits recording
//! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
//! implementations. However, there are some cases where it may be useful to record
//! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
//! user-defined `struct` and `enum` types without having to format them as
//! unstructured text.
//!
//! To address `Value`'s limitations, `tracing` offers experimental support for
//! the [`valuable`] crate, which provides object-safe inspection of structured
//! values. User-defined types can implement the [`valuable::Valuable`] trait,
//! and be recorded as a `tracing` field by calling their [`as_value`] method.
//! If the [`Subscriber`] also supports the `valuable` crate, it can
//! then visit those types fields as structured values using `valuable`.
//!
//! <pre class="ignore" style="white-space:normal;font:inherit;">
//! <strong>Note</strong>: <code>valuable</code> support is an
//! <a href = "../index.html#unstable-features">unstable feature</a>. See
//! the documentation on unstable features for details on how to enable it.
//! </pre>
//!
//! For example:
//! ```ignore
//! // Derive `Valuable` for our types:
//! use valuable::Valuable;
//!
//! #[derive(Clone, Debug, Valuable)]
//! struct User {
//! name: String,
//! age: u32,
//! address: Address,
//! }
//!
//! #[derive(Clone, Debug, Valuable)]
//! struct Address {
//! country: String,
//! city: String,
//! street: String,
//! }
//!
//! let user = User {
//! name: "Arwen Undomiel".to_string(),
//! age: 3000,
//! address: Address {
//! country: "Middle Earth".to_string(),
//! city: "Rivendell".to_string(),
//! street: "leafy lane".to_string(),
//! },
//! };
//!
//! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
//! // to traverse its fields as a nested, typed structure:
//! tracing::info!(current_user = user.as_value());
//! ```
//!
//! Alternatively, the [`valuable()`] function may be used to convert a type
//! implementing [`Valuable`] into a `tracing` field value.
//!
//! When the `valuable` feature is enabled, the [`Visit`] trait will include an
//! optional [`record_value`] method. `Visit` implementations that wish to
//! record `valuable` values can implement this method with custom behavior.
//! If a visitor does not implement `record_value`, the [`valuable::Value`] will
//! be forwarded to the visitor's [`record_debug`] method.
//!
//! [`valuable`]: https://crates.io/crates/valuable
//! [`as_value`]: valuable::Valuable::as_value
//! [`Subscriber`]: crate::Subscriber
//! [`record_value`]: Visit::record_value
//! [`record_debug`]: Visit::record_debug
//!
//! [`Value`]: trait.Value.html
//! [span]: ../span/
Expand Down Expand Up @@ -189,7 +262,7 @@ pub trait Visit {
/// [`valuable`]: https://docs.rs/valuable
#[cfg(all(tracing_unstable, feature = "valuable"))]
#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
fn record_value(&mut self, field: &Field, value: &dyn valuable::Valuable) {
fn record_value(&mut self, field: &Field, value: &valuable::Value<'_>) {
self.record_debug(field, &value)
}

Expand Down Expand Up @@ -258,14 +331,6 @@ pub struct DisplayValue<T: fmt::Display>(T);
#[derive(Clone)]
pub struct DebugValue<T: fmt::Debug>(T);

/// A `Value` which serializes using [`Valuable`].
///
/// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
#[derive(Clone)]
#[cfg(all(tracing_unstable, feature = "valuable"))]
#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
pub struct ValuableValue<T: valuable::Valuable>(T);

/// Wraps a type implementing `fmt::Display` as a `Value` that can be
/// recorded using its `Display` implementation.
pub fn display<T>(t: T) -> DisplayValue<T>
Expand All @@ -290,11 +355,11 @@ where
/// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
#[cfg(all(tracing_unstable, feature = "valuable"))]
#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
pub fn valuable<T>(t: T) -> ValuableValue<T>
pub fn valuable<T>(t: &T) -> valuable::Value<'_>
where
T: valuable::Valuable,
{
ValuableValue(t)
t.as_value()
}

// ===== impl Visit =====
Expand Down Expand Up @@ -572,21 +637,24 @@ impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
// ===== impl ValuableValue =====

#[cfg(all(tracing_unstable, feature = "valuable"))]
impl<T: valuable::Valuable> crate::sealed::Sealed for ValuableValue<T> {}
impl crate::sealed::Sealed for valuable::Value<'_> {}

#[cfg(all(tracing_unstable, feature = "valuable"))]
#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
impl<T: valuable::Valuable> Value for ValuableValue<T> {
impl Value for valuable::Value<'_> {
fn record(&self, key: &Field, visitor: &mut dyn Visit) {
visitor.record_value(key, &self.0)
visitor.record_value(key, self)
}
}

#[cfg(all(tracing_unstable, feature = "valuable"))]
impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {}

#[cfg(all(tracing_unstable, feature = "valuable"))]
#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
impl<T: valuable::Valuable> fmt::Debug for ValuableValue<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", &self.0 as &dyn valuable::Valuable)
impl Value for &'_ dyn valuable::Valuable {
fn record(&self, key: &Field, visitor: &mut dyn Visit) {
visitor.record_value(key, &self.as_value())
}
}

Expand Down
35 changes: 33 additions & 2 deletions tracing-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
//! be used with the `tracing` ecosystem. It includes a collection of
//! `Subscriber` implementations, as well as utility and adapter crates.
//!
//! ### Crate Feature Flags
//! ## Crate Feature Flags
//!
//! The following crate feature flags are available:
//! The following crate [feature flags] are available:
//!
//! * `std`: Depend on the Rust standard library (enabled by default).
//!
Expand All @@ -58,6 +58,37 @@
//!
//! **Note**:`tracing-core`'s `no_std` support requires `liballoc`.
//!
//! ### Unstable Features
//!
//! These feature flags enable **unstable** features. The public API may break in 0.1.x
//! releases. To enable these features, the `--cfg tracing_unstable` must be passed to
//! `rustc` when compiling.
//!
//! The following unstable feature flags are currently available:
//!
//! * `valuable`: Enables support for recording [field values] using the
//! [`valuable`] crate.
//!
//! #### Enabling Unstable Features
//!
//! The easiest way to set the `tracing_unstable` cfg is to use the `RUSTFLAGS`
//! env variable when running `cargo` commands:
//!
//! ```shell
//! RUSTFLAGS="--cfg tracing_unstable" cargo build
//! ```
//! Alternatively, the following can be added to the `.cargo/config` file in a
//! project to automatically enable the cfg flag for that project:
//!
//! ```toml
//! [build]
//! rustflags = ["--cfg", "tracing_unstable"]
//! ```
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//! [field values]: crate::field
//! [`valuable`]: https://crates.io/crates/valuable
//!
//! ## Supported Rust Versions
//!
//! Tracing is built against the latest stable release. The minimum supported
Expand Down
8 changes: 6 additions & 2 deletions tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ edition = "2018"
rust-version = "1.42.0"

[dependencies]
tracing-core = { path = "../tracing-core", version = "0.1.21", default-features = false }
tracing-core = { path = "../tracing-core", version = "0.1.22", default-features = false }
log = { version = "0.4", optional = true }
tracing-attributes = { path = "../tracing-attributes", version = "0.1.18", optional = true }
cfg-if = "1.0.0"
Expand Down Expand Up @@ -81,4 +81,8 @@ maintenance = { status = "actively-developed" }

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
# enable unstable features in the documentation
rustdoc-args = ["--cfg", "docsrs", "--cfg", "tracing_unstable"]
# it's necessary to _also_ pass `--cfg tracing_unstable` to rustc, or else
# dependencies will not be enabled, and the docs build will fail.
rustc-args = ["--cfg", "tracing_unstable"]
114 changes: 113 additions & 1 deletion tracing/src/field.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,116 @@
//! Structured data associated with `Span`s and `Event`s.
//! `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`].
//!
//! # `Value`s and `Subscriber`s
//!
//! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s.
//! The set of field keys on a given span or is defined on its [`Metadata`].
//! When a span is created, it provides [`Attributes`] to the `Subscriber`'s
//! [`new_span`] method, containing any fields whose values were provided when
//! the span was created; and may call the `Subscriber`'s [`record`] method
//! with additional [`Record`]s if values are added for more of its fields.
//! Similarly, the [`Event`] type passed to the subscriber's [`event`] method
//! will contain any fields attached to each event.
//!
//! `tracing` represents values as either one of a set of Rust primitives
//! (`i64`, `u64`, `f64`, `bool`, and `&str`) or using a `fmt::Display` or
//! `fmt::Debug` implementation. `Subscriber`s are provided these primitive
//! value types as `dyn Value` trait objects.
//!
//! These trait objects can be formatted using `fmt::Debug`, but may also be
//! recorded as typed data by calling the [`Value::record`] method on these
//! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
//! represents the behavior used to record values of various types. For example,
//! an implementation of `Visit` might record integers by incrementing counters
//! for their field names rather than printing them.
//!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removing an extra space I just noticed.

Suggested change
//!

//!
//! # Using `valuable`
//!
//! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
//! number of Rust primitives as typed values, and only permits recording
//! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
//! implementations. However, there are some cases where it may be useful to record
//! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
//! user-defined `struct` and `enum` types without having to format them as
//! unstructured text.
//!
//! To address `Value`'s limitations, `tracing` offers experimental support for
//! the [`valuable`] crate, which provides object-safe inspection of structured
//! values. User-defined types can implement the [`valuable::Valuable`] trait,
//! and be recorded as a `tracing` field by calling their [`as_value`] method.
//! If the [`Subscriber`] also supports the `valuable` crate, it can
//! then visit those types fields as structured values using `valuable`.
//!
//! <pre class="ignore" style="white-space:normal;font:inherit;">
//! <strong>Note</strong>: <code>valuable</code> support is an
//! <a href = "../index.html#unstable-features">unstable feature</a>. See
//! the documentation on unstable features for details on how to enable it.
//! </pre>
//!
//! For example:
//! ```ignore
//! // Derive `Valuable` for our types:
//! use valuable::Valuable;
//!
//! #[derive(Clone, Debug, Valuable)]
//! struct User {
//! name: String,
//! age: u32,
//! address: Address,
//! }
//!
//! #[derive(Clone, Debug, Valuable)]
//! struct Address {
//! country: String,
//! city: String,
//! street: String,
//! }
//!
//! let user = User {
//! name: "Arwen Undomiel".to_string(),
//! age: 3000,
//! address: Address {
//! country: "Middle Earth".to_string(),
//! city: "Rivendell".to_string(),
//! street: "leafy lane".to_string(),
//! },
//! };
//!
//! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
//! // to traverse its fields as a nested, typed structure:
//! tracing::info!(current_user = user.as_value());
//! ```
//!
//! Alternatively, the [`valuable()`] function may be used to convert a type
//! implementing [`Valuable`] into a `tracing` field value.
//!
//! When the `valuable` feature is enabled, the [`Visit`] trait will include an
//! optional [`record_value`] method. `Visit` implementations that wish to
//! record `valuable` values can implement this method with custom behavior.
//! If a visitor does not implement `record_value`, the [`valuable::Value`] will
//! be forwarded to the visitor's [`record_debug`] method.
//!
//! [`fmt::Debug`]: std::fmt::Debug
//! [`fmt::Display`]: std::fmt::Debug
//! [`valuable`]: https://crates.io/crates/valuable
//! [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
//! [`as_value`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html#tymethod.as_value
//! [`valuable::Value`]: https://docs.rs/valuable/latest/valuable/enum.Value.html
//! [`Subscriber`]: crate::Subscriber
//! [`record_value`]: Visit::record_value
//! [`record_debug`]: Visit::record_debug
//! [span]: mod@crate::span
//! [`Event`]: crate::event::Event
//! [`Metadata`]: crate::Metadata
//! [`Attributes`]: crate::span::Attributes
//! [`Record`]: crate::span::Record
//! [`new_span`]: crate::Subscriber::new_span
//! [`record`]: crate::Subscriber::record
//! [`event`]: crate::Subscriber::event
pub use tracing_core::field::*;

use crate::Metadata;
Expand Down