Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions tracing-attributes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ proc-macro = true
# This feature flag is no longer necessary.
async-await = []

# Enable experimental support for valuable crate
valuable = ["tracing/valuable"]

[dependencies]
proc-macro2 = "1.0.60"
syn = { version = "2.0", default-features = false, features = [
Expand Down Expand Up @@ -65,3 +68,11 @@ maintenance = { status = "experimental" }

[lints]
workspace = true

[package.metadata.docs.rs]
all-features = true
# 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"]
49 changes: 28 additions & 21 deletions tracing-attributes/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ impl EventArgs {
}
}

#[cfg(all(tracing_unstable, feature = "valuable"))]
const FORMATTING_MODE_ERR: &str =
"unknown event formatting mode, expected either `Debug`, `Valuable` or `Display`";
#[cfg(not(all(tracing_unstable, feature = "valuable")))]
const FORMATTING_MODE_ERR: &str =
"unknown event formatting mode, expected either `Debug` or `Display`";

impl Parse for EventArgs {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
if !input.peek(syn::token::Paren) {
Expand All @@ -179,28 +186,26 @@ impl Parse for EventArgs {
let content;
let _ = syn::parenthesized!(content in input);
let mut result = Self::default();
let mut parse_one_arg =
|| {
let lookahead = content.lookahead1();
if lookahead.peek(kw::level) {
if result.level.is_some() {
return Err(content.error("expected only a single `level` argument"));
}
result.level = Some(content.parse()?);
} else if result.mode != FormatMode::default() {
return Err(content.error("expected only a single format argument"));
} else if let Some(ident) = content.parse::<Option<Ident>>()? {
match ident.to_string().as_str() {
"Debug" => result.mode = FormatMode::Debug,
"Display" => result.mode = FormatMode::Display,
_ => return Err(syn::Error::new(
ident.span(),
"unknown event formatting mode, expected either `Debug` or `Display`",
)),
}
let mut parse_one_arg = || {
let lookahead = content.lookahead1();
if lookahead.peek(kw::level) {
if result.level.is_some() {
return Err(content.error("expected only a single `level` argument"));
}
Ok(())
};
result.level = Some(content.parse()?);
} else if result.mode != FormatMode::default() {
return Err(content.error("expected only a single format argument"));
} else if let Some(ident) = content.parse::<Option<Ident>>()? {
match ident.to_string().as_str() {
"Debug" => result.mode = FormatMode::Debug,
"Display" => result.mode = FormatMode::Display,
#[cfg(all(tracing_unstable, feature = "valuable"))]
"Valuable" => result.mode = FormatMode::Valuable,
_ => return Err(syn::Error::new(ident.span(), FORMATTING_MODE_ERR)),
}
}
Ok(())
};
parse_one_arg()?;
if !content.is_empty() {
if content.lookahead1().peek(Token![,]) {
Expand Down Expand Up @@ -301,6 +306,8 @@ pub(crate) enum FormatMode {
Default,
Display,
Debug,
#[cfg(all(tracing_unstable, feature = "valuable"))]
Valuable,
}

#[derive(Clone, Debug)]
Expand Down
8 changes: 8 additions & 0 deletions tracing-attributes/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ fn gen_block<B: ToTokens>(
FormatMode::Debug => Some(quote!(
::tracing::event!(target: #target, #level_tokens, error = ?e)
)),
#[cfg(all(tracing_unstable, feature = "valuable"))]
FormatMode::Valuable => Some(quote!(::tracing::event!(
target: #target, #level_tokens, error = ::tracing::field::valuable(&e),
))),
}
}
_ => None,
Expand All @@ -290,6 +294,10 @@ fn gen_block<B: ToTokens>(
FormatMode::Default | FormatMode::Debug => Some(quote!(
::tracing::event!(target: #target, #level_tokens, return = ?x)
)),
#[cfg(all(tracing_unstable, feature = "valuable"))]
FormatMode::Valuable => Some(quote!(::tracing::event!(
target: #target, #level_tokens, return = ::tracing::field::valuable(&x),
))),
}
}
_ => None,
Expand Down
45 changes: 45 additions & 0 deletions tracing-attributes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@
//! supported compiler version is not considered a semver breaking change as
//! long as doing so complies with this policy.
//!
//! ## Experimental features
//!
//! The [`#[instrument]`][instrument] attribute supports the experimental
//! `valuable` cargo feature to allow recording both the return value and the
//! error values returned in the [`variant@Result::Err`] variant using the
//! [valuable::Valuable][`Valuable`] trait. To take advantage of this feature
//! you also need to enable [unstable features] of the [`tracing`] crate.
//!
//! [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
//! [unstable features]:
//! https://docs.rs/tracing/latest/tracing/index.html#unstable-features
//!
#![doc(
html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/logo-type.png",
html_favicon_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/favicon.ico",
Expand Down Expand Up @@ -465,6 +477,20 @@ mod expand;
/// }
/// ```
///
/// If the experimental support for the [`valuable`] crate is enabled using the `valuable` cargo
/// feature, and the return type implements the [`Valuable` trait] it can be recorded using the
/// [`tracing::field::valuable`] implementation, by writing `ret(Valuable)`:
///
/// ```
/// # use tracing_attributes::instrument;
/// #[instrument(ret(Valuable))]
/// fn my_function() -> i32 {
/// 42
/// }
/// ```
/// **Note**: To enable support for [`valuable`] you must first enable unstable tracing features.
/// See [unstable features] documentation of the `tracing` crate.
///
/// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, adding
/// `err` or `err(Display)` will emit error events when the function returns `Err`:
///
Expand Down Expand Up @@ -501,6 +527,21 @@ mod expand;
/// }
/// ```
///
/// For error values that implement the [`Valuable` trait] it is also possible to record them as a
/// [`Valuable` trait] using the experimental [`valuable`] support by writing `err(Valuable)`:
///
/// ```
/// # use tracing_attributes::instrument;
/// # use std::error::Error;
/// #[instrument(err(Valuable))]
/// fn my_function(arg: usize) -> Result<(), &'static dyn Error> {
/// Ok(())
/// }
/// ```
///
/// **Note**: this requires enabling both the `valuable` cargo feature and [unstable features]
/// of the `tracing` crate.
///
/// If a `target` is specified, both the `ret` and `err` arguments will emit outputs to
/// the declared target (or the default channel if `target` is not specified).
///
Expand Down Expand Up @@ -572,6 +613,10 @@ mod expand;
/// [`Level`]: https://docs.rs/tracing/latest/tracing/struct.Level.html
/// [`Level::TRACE`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.TRACE
/// [`Level::ERROR`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.ERROR
/// [unstable features]: https://docs.rs/tracing/latest/tracing/#unstable-features
/// [`valuable`]: https://docs.rs/valuable/latest/valuable/
/// [`Valuable` trait]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
/// [`tracing::field::valuable`]: https://docs.rs/tracing/latest/tracing/field/fn.valuable.html
#[proc_macro_attribute]
pub fn instrument(
args: proc_macro::TokenStream,
Expand Down
Loading