diff options
Diffstat (limited to 'vendor/tracing-subscriber/src/field')
-rw-r--r-- | vendor/tracing-subscriber/src/field/debug.rs | 111 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/field/delimited.rs | 184 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/field/display.rs | 117 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/field/mod.rs | 366 |
4 files changed, 778 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/src/field/debug.rs b/vendor/tracing-subscriber/src/field/debug.rs new file mode 100644 index 000000000..cc67d29fe --- /dev/null +++ b/vendor/tracing-subscriber/src/field/debug.rs @@ -0,0 +1,111 @@ +//! `MakeVisitor` wrappers for working with `fmt::Debug` fields. +use super::{MakeVisitor, VisitFmt, VisitOutput}; +use tracing_core::field::{Field, Visit}; + +use core::fmt; + +/// A visitor wrapper that ensures any `fmt::Debug` fields are formatted using +/// the alternate (`:#`) formatter. +#[derive(Debug, Clone)] +pub struct Alt<V>(V); + +// TODO(eliza): When `error` as a primitive type is stable, add a +// `DisplayErrors` wrapper... + +// === impl Alt === +// +impl<V> Alt<V> { + /// Wraps the provided visitor so that any `fmt::Debug` fields are formatted + /// using the alternative (`:#`) formatter. + pub fn new(inner: V) -> Self { + Alt(inner) + } +} + +impl<T, V> MakeVisitor<T> for Alt<V> +where + V: MakeVisitor<T>, +{ + type Visitor = Alt<V::Visitor>; + + #[inline] + fn make_visitor(&self, target: T) -> Self::Visitor { + Alt(self.0.make_visitor(target)) + } +} + +impl<V> Visit for Alt<V> +where + V: Visit, +{ + #[inline] + fn record_f64(&mut self, field: &Field, value: f64) { + self.0.record_f64(field, value) + } + + #[inline] + fn record_i64(&mut self, field: &Field, value: i64) { + self.0.record_i64(field, value) + } + + #[inline] + fn record_u64(&mut self, field: &Field, value: u64) { + self.0.record_u64(field, value) + } + + #[inline] + fn record_bool(&mut self, field: &Field, value: bool) { + self.0.record_bool(field, value) + } + + /// Visit a string value. + fn record_str(&mut self, field: &Field, value: &str) { + self.0.record_str(field, value) + } + + // TODO(eliza): add RecordError when stable + // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) { + // self.record_debug(field, &format_args!("{}", value)) + // } + + #[inline] + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + self.0.record_debug(field, &format_args!("{:#?}", value)) + } +} + +impl<V, O> VisitOutput<O> for Alt<V> +where + V: VisitOutput<O>, +{ + #[inline] + fn finish(self) -> O { + self.0.finish() + } +} + +feature! { + #![feature = "std"] + use super::VisitWrite; + use std::io; + + impl<V> VisitWrite for Alt<V> + where + V: VisitWrite, + { + #[inline] + fn writer(&mut self) -> &mut dyn io::Write { + self.0.writer() + } + } +} + +impl<V> VisitFmt for Alt<V> +where + V: VisitFmt, +{ + #[inline] + fn writer(&mut self) -> &mut dyn fmt::Write { + self.0.writer() + } +} diff --git a/vendor/tracing-subscriber/src/field/delimited.rs b/vendor/tracing-subscriber/src/field/delimited.rs new file mode 100644 index 000000000..98634cea9 --- /dev/null +++ b/vendor/tracing-subscriber/src/field/delimited.rs @@ -0,0 +1,184 @@ +//! A `MakeVisitor` wrapper that separates formatted fields with a delimiter. +use super::{MakeVisitor, VisitFmt, VisitOutput}; + +use core::fmt; +use tracing_core::field::{Field, Visit}; + +/// A `MakeVisitor` wrapper that wraps a visitor that writes formatted output so +/// that a delimiter is inserted between writing formatted field values. +#[derive(Debug, Clone)] +pub struct Delimited<D, V> { + delimiter: D, + inner: V, +} + +/// A visitor wrapper that inserts a delimiter after the wrapped visitor formats +/// a field value. +#[derive(Debug)] +pub struct VisitDelimited<D, V> { + delimiter: D, + seen: bool, + inner: V, + err: fmt::Result, +} + +// === impl Delimited === + +impl<D, V, T> MakeVisitor<T> for Delimited<D, V> +where + D: AsRef<str> + Clone, + V: MakeVisitor<T>, + V::Visitor: VisitFmt, +{ + type Visitor = VisitDelimited<D, V::Visitor>; + fn make_visitor(&self, target: T) -> Self::Visitor { + let inner = self.inner.make_visitor(target); + VisitDelimited::new(self.delimiter.clone(), inner) + } +} + +impl<D, V> Delimited<D, V> { + /// Returns a new [`MakeVisitor`] implementation that wraps `inner` so that + /// it will format each visited field separated by the provided `delimiter`. + /// + /// [`MakeVisitor`]: super::MakeVisitor + pub fn new(delimiter: D, inner: V) -> Self { + Self { delimiter, inner } + } +} + +// === impl VisitDelimited === + +impl<D, V> VisitDelimited<D, V> { + /// Returns a new [`Visit`] implementation that wraps `inner` so that + /// each formatted field is separated by the provided `delimiter`. + /// + /// [`Visit`]: tracing_core::field::Visit + pub fn new(delimiter: D, inner: V) -> Self { + Self { + delimiter, + inner, + seen: false, + err: Ok(()), + } + } + + fn delimit(&mut self) + where + V: VisitFmt, + D: AsRef<str>, + { + if self.err.is_err() { + return; + } + + if self.seen { + self.err = self.inner.writer().write_str(self.delimiter.as_ref()); + } + + self.seen = true; + } +} + +impl<D, V> Visit for VisitDelimited<D, V> +where + V: VisitFmt, + D: AsRef<str>, +{ + fn record_i64(&mut self, field: &Field, value: i64) { + self.delimit(); + self.inner.record_i64(field, value); + } + + fn record_u64(&mut self, field: &Field, value: u64) { + self.delimit(); + self.inner.record_u64(field, value); + } + + fn record_bool(&mut self, field: &Field, value: bool) { + self.delimit(); + self.inner.record_bool(field, value); + } + + fn record_str(&mut self, field: &Field, value: &str) { + self.delimit(); + self.inner.record_str(field, value); + } + + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + self.delimit(); + self.inner.record_debug(field, value); + } +} + +impl<D, V> VisitOutput<fmt::Result> for VisitDelimited<D, V> +where + V: VisitFmt, + D: AsRef<str>, +{ + fn finish(self) -> fmt::Result { + self.err?; + self.inner.finish() + } +} + +impl<D, V> VisitFmt for VisitDelimited<D, V> +where + V: VisitFmt, + D: AsRef<str>, +{ + fn writer(&mut self) -> &mut dyn fmt::Write { + self.inner.writer() + } +} + +#[cfg(test)] +#[cfg(all(test, feature = "alloc"))] +mod test { + use super::*; + use crate::field::test_util::*; + + #[test] + fn delimited_visitor() { + let mut s = String::new(); + let visitor = DebugVisitor::new(&mut s); + let mut visitor = VisitDelimited::new(", ", visitor); + + TestAttrs1::with(|attrs| attrs.record(&mut visitor)); + visitor.finish().unwrap(); + + assert_eq!( + s.as_str(), + "question=\"life, the universe, and everything\", tricky=true, can_you_do_it=true" + ); + } + + #[test] + fn delimited_new_visitor() { + let make = Delimited::new("; ", MakeDebug); + + TestAttrs1::with(|attrs| { + let mut s = String::new(); + { + let mut v = make.make_visitor(&mut s); + attrs.record(&mut v); + } + assert_eq!( + s.as_str(), + "question=\"life, the universe, and everything\"; tricky=true; can_you_do_it=true" + ); + }); + + TestAttrs2::with(|attrs| { + let mut s = String::new(); + { + let mut v = make.make_visitor(&mut s); + attrs.record(&mut v); + } + assert_eq!( + s.as_str(), + "question=None; question.answer=42; tricky=true; can_you_do_it=false" + ); + }); + } +} diff --git a/vendor/tracing-subscriber/src/field/display.rs b/vendor/tracing-subscriber/src/field/display.rs new file mode 100644 index 000000000..78a039ce1 --- /dev/null +++ b/vendor/tracing-subscriber/src/field/display.rs @@ -0,0 +1,117 @@ +//! `MakeVisitor` wrappers for working with `fmt::Display` fields. +use super::{MakeVisitor, VisitFmt, VisitOutput}; +use tracing_core::field::{Field, Visit}; + +use core::fmt; + +/// A visitor wrapper that ensures any strings named "message" are formatted +/// using `fmt::Display` +#[derive(Debug, Clone)] +pub struct Messages<V>(V); + +// TODO(eliza): When `error` as a primitive type is stable, add a +// `DisplayErrors` wrapper... + +// === impl Messages === +// +impl<V> Messages<V> { + /// Returns a new [`MakeVisitor`] implementation that will wrap `inner` so + /// that any strings named `message` are formatted using `fmt::Display`. + /// + /// [`MakeVisitor`]: super::MakeVisitor + pub fn new(inner: V) -> Self { + Messages(inner) + } +} + +impl<T, V> MakeVisitor<T> for Messages<V> +where + V: MakeVisitor<T>, +{ + type Visitor = Messages<V::Visitor>; + + #[inline] + fn make_visitor(&self, target: T) -> Self::Visitor { + Messages(self.0.make_visitor(target)) + } +} + +impl<V> Visit for Messages<V> +where + V: Visit, +{ + #[inline] + fn record_f64(&mut self, field: &Field, value: f64) { + self.0.record_f64(field, value) + } + + #[inline] + fn record_i64(&mut self, field: &Field, value: i64) { + self.0.record_i64(field, value) + } + + #[inline] + fn record_u64(&mut self, field: &Field, value: u64) { + self.0.record_u64(field, value) + } + + #[inline] + fn record_bool(&mut self, field: &Field, value: bool) { + self.0.record_bool(field, value) + } + + /// Visit a string value. + fn record_str(&mut self, field: &Field, value: &str) { + if field.name() == "message" { + self.0.record_debug(field, &format_args!("{}", value)) + } else { + self.0.record_str(field, value) + } + } + + // TODO(eliza): add RecordError when stable + // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) { + // self.record_debug(field, &format_args!("{}", value)) + // } + + #[inline] + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + self.0.record_debug(field, value) + } +} + +impl<V, O> VisitOutput<O> for Messages<V> +where + V: VisitOutput<O>, +{ + #[inline] + fn finish(self) -> O { + self.0.finish() + } +} + +feature! { + #![feature = "std"] + use super::VisitWrite; + use std::io; + + impl<V> VisitWrite for Messages<V> + where + V: VisitWrite, + { + #[inline] + fn writer(&mut self) -> &mut dyn io::Write { + self.0.writer() + } + } +} + +impl<V> VisitFmt for Messages<V> +where + V: VisitFmt, +{ + #[inline] + fn writer(&mut self) -> &mut dyn fmt::Write { + self.0.writer() + } +} diff --git a/vendor/tracing-subscriber/src/field/mod.rs b/vendor/tracing-subscriber/src/field/mod.rs new file mode 100644 index 000000000..5dfddb362 --- /dev/null +++ b/vendor/tracing-subscriber/src/field/mod.rs @@ -0,0 +1,366 @@ +//! Utilities for working with [fields] and [field visitors]. +//! +//! [fields]: tracing_core::field +//! [field visitors]: tracing_core::field::Visit +use core::{fmt, marker::PhantomData}; +pub use tracing_core::field::Visit; +use tracing_core::{ + span::{Attributes, Record}, + Event, +}; +pub mod debug; +pub mod delimited; +pub mod display; + +/// Creates new [visitors]. +/// +/// A type implementing `MakeVisitor` represents a composable factory for types +/// implementing the [`Visit` trait][visitors]. The `MakeVisitor` trait defines +/// a single function, `make_visitor`, which takes in a `T`-typed `target` and +/// returns a type implementing `Visit` configured for that target. A target may +/// be a string, output stream, or data structure that the visitor will record +/// data to, configuration variables that determine the visitor's behavior, or +/// `()` when no input is required to produce a visitor. +/// +/// [visitors]: tracing_core::field::Visit +pub trait MakeVisitor<T> { + /// The visitor type produced by this `MakeVisitor`. + type Visitor: Visit; + + /// Make a new visitor for the provided `target`. + fn make_visitor(&self, target: T) -> Self::Visitor; +} + +/// A [visitor] that produces output once it has visited a set of fields. +/// +/// [visitor]: tracing_core::field::Visit +pub trait VisitOutput<Out>: Visit { + /// Completes the visitor, returning any output. + /// + /// This is called once a full set of fields has been visited. + fn finish(self) -> Out; + + /// Visit a set of fields, and return the output of finishing the visitor + /// once the fields have been visited. + fn visit<R>(mut self, fields: &R) -> Out + where + R: RecordFields, + Self: Sized, + { + fields.record(&mut self); + self.finish() + } +} + +/// Extension trait implemented by types which can be recorded by a [visitor]. +/// +/// This allows writing code that is generic over `tracing_core`'s +/// [`span::Attributes`][attr], [`span::Record`][rec], and [`Event`][event] +/// types. These types all provide inherent `record` methods that allow a +/// visitor to record their fields, but there is no common trait representing this. +/// +/// With `RecordFields`, we can write code like this: +/// ``` +/// use tracing_core::field::Visit; +/// # use tracing_core::field::Field; +/// use tracing_subscriber::field::RecordFields; +/// +/// struct MyVisitor { +/// // ... +/// } +/// # impl MyVisitor { fn new() -> Self { Self{} } } +/// impl Visit for MyVisitor { +/// // ... +/// # fn record_debug(&mut self, _: &Field, _: &dyn std::fmt::Debug) {} +/// } +/// +/// fn record_with_my_visitor<R>(r: R) +/// where +/// R: RecordFields, +/// { +/// let mut visitor = MyVisitor::new(); +/// r.record(&mut visitor); +/// } +/// ``` +/// [visitor]: tracing_core::field::Visit +/// [attr]: tracing_core::span::Attributes +/// [rec]: tracing_core::span::Record +/// [event]: tracing_core::event::Event +pub trait RecordFields: crate::sealed::Sealed<RecordFieldsMarker> { + /// Record all the fields in `self` with the provided `visitor`. + fn record(&self, visitor: &mut dyn Visit); +} + +/// Extension trait implemented for all `MakeVisitor` implementations that +/// produce a visitor implementing `VisitOutput`. +pub trait MakeOutput<T, Out> +where + Self: MakeVisitor<T> + crate::sealed::Sealed<(T, Out)>, + Self::Visitor: VisitOutput<Out>, +{ + /// Visits all fields in `fields` with a new visitor constructed from + /// `target`. + fn visit_with<F>(&self, target: T, fields: &F) -> Out + where + F: RecordFields, + { + self.make_visitor(target).visit(fields) + } +} + +feature! { + #![feature = "std"] + use std::io; + + /// Extension trait implemented by visitors to indicate that they write to an + /// `io::Write` instance, and allow access to that writer. + pub trait VisitWrite: VisitOutput<Result<(), io::Error>> { + /// Returns the writer that this visitor writes to. + fn writer(&mut self) -> &mut dyn io::Write; + } +} + +/// Extension trait implemented by visitors to indicate that they write to a +/// `fmt::Write` instance, and allow access to that writer. +pub trait VisitFmt: VisitOutput<fmt::Result> { + /// Returns the formatter that this visitor writes to. + fn writer(&mut self) -> &mut dyn fmt::Write; +} + +/// Extension trait providing `MakeVisitor` combinators. +pub trait MakeExt<T> +where + Self: MakeVisitor<T> + Sized, + Self: crate::sealed::Sealed<MakeExtMarker<T>>, +{ + /// Wraps `self` so that any `fmt::Debug` fields are recorded using the + /// alternate formatter (`{:#?}`). + fn debug_alt(self) -> debug::Alt<Self> { + debug::Alt::new(self) + } + + /// Wraps `self` so that any string fields named "message" are recorded + /// using `fmt::Display`. + fn display_messages(self) -> display::Messages<Self> { + display::Messages::new(self) + } + + /// Wraps `self` so that when fields are formatted to a writer, they are + /// separated by the provided `delimiter`. + fn delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self> + where + D: AsRef<str> + Clone, + Self::Visitor: VisitFmt, + { + delimited::Delimited::new(delimiter, self) + } +} + +// === impl RecordFields === + +impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {} +impl<'a> RecordFields for Event<'a> { + fn record(&self, visitor: &mut dyn Visit) { + Event::record(self, visitor) + } +} + +impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Attributes<'a> {} +impl<'a> RecordFields for Attributes<'a> { + fn record(&self, visitor: &mut dyn Visit) { + Attributes::record(self, visitor) + } +} + +impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Record<'a> {} +impl<'a> RecordFields for Record<'a> { + fn record(&self, visitor: &mut dyn Visit) { + Record::record(self, visitor) + } +} + +impl<'a, F> crate::sealed::Sealed<RecordFieldsMarker> for &'a F where F: RecordFields {} +impl<'a, F> RecordFields for &'a F +where + F: RecordFields, +{ + fn record(&self, visitor: &mut dyn Visit) { + F::record(*self, visitor) + } +} + +// === blanket impls === + +impl<T, V, F> MakeVisitor<T> for F +where + F: Fn(T) -> V, + V: Visit, +{ + type Visitor = V; + fn make_visitor(&self, target: T) -> Self::Visitor { + (self)(target) + } +} + +impl<T, Out, M> crate::sealed::Sealed<(T, Out)> for M +where + M: MakeVisitor<T>, + M::Visitor: VisitOutput<Out>, +{ +} + +impl<T, Out, M> MakeOutput<T, Out> for M +where + M: MakeVisitor<T>, + M::Visitor: VisitOutput<Out>, +{ +} + +impl<T, M> crate::sealed::Sealed<MakeExtMarker<T>> for M where M: MakeVisitor<T> + Sized {} + +impl<T, M> MakeExt<T> for M +where + M: MakeVisitor<T> + Sized, + M: crate::sealed::Sealed<MakeExtMarker<T>>, +{ +} + +#[derive(Debug)] +#[doc(hidden)] +pub struct MakeExtMarker<T> { + _p: PhantomData<T>, +} + +#[derive(Debug)] +#[doc(hidden)] +pub struct RecordFieldsMarker { + _p: (), +} + +#[cfg(all(test, feature = "alloc"))] +#[macro_use] +pub(in crate::field) mod test_util { + use super::*; + pub(in crate::field) use alloc::string::String; + use tracing_core::{ + callsite::Callsite, + field::{Field, Value}, + metadata::{Kind, Level, Metadata}, + }; + + pub(crate) struct TestAttrs1; + pub(crate) struct TestAttrs2; + + impl TestAttrs1 { + pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T { + let fieldset = TEST_META_1.fields(); + let values = &[ + ( + &fieldset.field("question").unwrap(), + Some(&"life, the universe, and everything" as &dyn Value), + ), + (&fieldset.field("question.answer").unwrap(), None), + ( + &fieldset.field("tricky").unwrap(), + Some(&true as &dyn Value), + ), + ( + &fieldset.field("can_you_do_it").unwrap(), + Some(&true as &dyn Value), + ), + ]; + let valueset = fieldset.value_set(values); + let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset); + f(attrs) + } + } + + impl TestAttrs2 { + pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T { + let fieldset = TEST_META_1.fields(); + let none = tracing_core::field::debug(&Option::<&str>::None); + let values = &[ + ( + &fieldset.field("question").unwrap(), + Some(&none as &dyn Value), + ), + ( + &fieldset.field("question.answer").unwrap(), + Some(&42 as &dyn Value), + ), + ( + &fieldset.field("tricky").unwrap(), + Some(&true as &dyn Value), + ), + ( + &fieldset.field("can_you_do_it").unwrap(), + Some(&false as &dyn Value), + ), + ]; + let valueset = fieldset.value_set(values); + let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset); + f(attrs) + } + } + + struct TestCallsite1; + static TEST_CALLSITE_1: &'static dyn Callsite = &TestCallsite1; + static TEST_META_1: Metadata<'static> = tracing_core::metadata! { + name: "field_test1", + target: module_path!(), + level: Level::INFO, + fields: &["question", "question.answer", "tricky", "can_you_do_it"], + callsite: TEST_CALLSITE_1, + kind: Kind::SPAN, + }; + + impl Callsite for TestCallsite1 { + fn set_interest(&self, _: tracing_core::subscriber::Interest) { + unimplemented!() + } + + fn metadata(&self) -> &Metadata<'_> { + &TEST_META_1 + } + } + + pub(crate) struct MakeDebug; + pub(crate) struct DebugVisitor<'a> { + writer: &'a mut dyn fmt::Write, + err: fmt::Result, + } + + impl<'a> DebugVisitor<'a> { + pub(crate) fn new(writer: &'a mut dyn fmt::Write) -> Self { + Self { + writer, + err: Ok(()), + } + } + } + + impl<'a> Visit for DebugVisitor<'a> { + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + write!(self.writer, "{}={:?}", field, value).unwrap(); + } + } + + impl<'a> VisitOutput<fmt::Result> for DebugVisitor<'a> { + fn finish(self) -> fmt::Result { + self.err + } + } + + impl<'a> VisitFmt for DebugVisitor<'a> { + fn writer(&mut self) -> &mut dyn fmt::Write { + self.writer + } + } + + impl<'a> MakeVisitor<&'a mut dyn fmt::Write> for MakeDebug { + type Visitor = DebugVisitor<'a>; + fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> { + DebugVisitor::new(w) + } + } +} |