12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199 |
- //! `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.
- //!
- //!
- //! # 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
- //!
- //! [span]: super::span
- //! [`Event`]: super::event::Event
- //! [`Metadata`]: super::metadata::Metadata
- //! [`Attributes`]: super::span::Attributes
- //! [`Record`]: super::span::Record
- //! [`new_span`]: super::subscriber::Subscriber::new_span
- //! [`record`]: super::subscriber::Subscriber::record
- //! [`event`]: super::subscriber::Subscriber::event
- //! [`Value::record`]: Value::record
- use crate::callsite;
- use crate::stdlib::{
- borrow::Borrow,
- fmt,
- hash::{Hash, Hasher},
- num,
- ops::Range,
- };
- use self::private::ValidLen;
- /// An opaque key allowing _O_(1) access to a field in a `Span`'s key-value
- /// data.
- ///
- /// As keys are defined by the _metadata_ of a span, rather than by an
- /// individual instance of a span, a key may be used to access the same field
- /// across all instances of a given span with the same metadata. Thus, when a
- /// subscriber observes a new span, it need only access a field by name _once_,
- /// and use the key for that name for all other accesses.
- #[derive(Debug)]
- pub struct Field {
- i: usize,
- 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.
- names: &'static [&'static str],
- /// The callsite where the described span originates.
- callsite: callsite::Identifier,
- }
- /// A set of fields and values for a span.
- pub struct ValueSet<'a> {
- values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)],
- fields: &'a FieldSet,
- }
- /// An iterator over a set of fields.
- #[derive(Debug)]
- pub struct Iter {
- idxs: Range<usize>,
- fields: FieldSet,
- }
- /// Visits typed values.
- ///
- /// An instance of `Visit` ("a visitor") represents the logic necessary to
- /// record field values of various types. When an implementor of [`Value`] is
- /// [recorded], it calls the appropriate method on the provided visitor to
- /// indicate the type that value should be recorded as.
- ///
- /// When a [`Subscriber`] implementation [records an `Event`] or a
- /// [set of `Value`s added to a `Span`], it can pass an `&mut Visit` to the
- /// `record` method on the provided [`ValueSet`] or [`Event`]. This visitor
- /// will then be used to record all the field-value pairs present on that
- /// `Event` or `ValueSet`.
- ///
- /// # Examples
- ///
- /// A simple visitor that writes to a string might be implemented like so:
- /// ```
- /// # extern crate tracing_core as tracing;
- /// use std::fmt::{self, Write};
- /// use tracing::field::{Value, Visit, Field};
- /// pub struct StringVisitor<'a> {
- /// string: &'a mut String,
- /// }
- ///
- /// impl<'a> Visit for StringVisitor<'a> {
- /// fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
- /// write!(self.string, "{} = {:?}; ", field.name(), value).unwrap();
- /// }
- /// }
- /// ```
- /// This visitor will format each recorded value using `fmt::Debug`, and
- /// append the field name and formatted value to the provided string,
- /// regardless of the type of the recorded value. When all the values have
- /// been recorded, the `StringVisitor` may be dropped, allowing the string
- /// to be printed or stored in some other data structure.
- ///
- /// The `Visit` trait provides default implementations for `record_i64`,
- /// `record_u64`, `record_bool`, `record_str`, and `record_error`, which simply
- /// forward the recorded value to `record_debug`. Thus, `record_debug` is the
- /// only method which a `Visit` implementation *must* implement. However,
- /// visitors may override the default implementations of these functions in
- /// order to implement type-specific behavior.
- ///
- /// Additionally, when a visitor receives a value of a type it does not care
- /// about, it is free to ignore those values completely. For example, a
- /// visitor which only records numeric data might look like this:
- ///
- /// ```
- /// # extern crate tracing_core as tracing;
- /// # use std::fmt::{self, Write};
- /// # use tracing::field::{Value, Visit, Field};
- /// pub struct SumVisitor {
- /// sum: i64,
- /// }
- ///
- /// impl Visit for SumVisitor {
- /// fn record_i64(&mut self, _field: &Field, value: i64) {
- /// self.sum += value;
- /// }
- ///
- /// fn record_u64(&mut self, _field: &Field, value: u64) {
- /// self.sum += value as i64;
- /// }
- ///
- /// fn record_debug(&mut self, _field: &Field, _value: &fmt::Debug) {
- /// // Do nothing
- /// }
- /// }
- /// ```
- ///
- /// This visitor (which is probably not particularly useful) keeps a running
- /// sum of all the numeric values it records, and ignores all other values. A
- /// more practical example of recording typed values is presented in
- /// `examples/counters.rs`, which demonstrates a very simple metrics system
- /// implemented using `tracing`.
- ///
- /// <div class="example-wrap" style="display:inline-block">
- /// <pre class="ignore" style="white-space:normal;font:inherit;">
- /// <strong>Note</strong>: The <code>record_error</code> trait method is only
- /// available when the Rust standard library is present, as it requires the
- /// <code>std::error::Error</code> trait.
- /// </pre></div>
- ///
- /// [recorded]: Value::record
- /// [`Subscriber`]: super::subscriber::Subscriber
- /// [records an `Event`]: super::subscriber::Subscriber::event
- /// [set of `Value`s added to a `Span`]: super::subscriber::Subscriber::record
- /// [`Event`]: super::event::Event
- pub trait Visit {
- /// Visits an arbitrary type implementing the [`valuable`] crate's `Valuable` trait.
- ///
- /// [`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: valuable::Value<'_>) {
- self.record_debug(field, &value)
- }
- /// Visit a double-precision floating point value.
- fn record_f64(&mut self, field: &Field, value: f64) {
- self.record_debug(field, &value)
- }
- /// Visit a signed 64-bit integer value.
- fn record_i64(&mut self, field: &Field, value: i64) {
- self.record_debug(field, &value)
- }
- /// Visit an unsigned 64-bit integer value.
- fn record_u64(&mut self, field: &Field, value: u64) {
- self.record_debug(field, &value)
- }
- /// Visit a boolean value.
- fn record_bool(&mut self, field: &Field, value: bool) {
- self.record_debug(field, &value)
- }
- /// Visit a string value.
- fn record_str(&mut self, field: &Field, value: &str) {
- self.record_debug(field, &value)
- }
- /// Records a type implementing `Error`.
- ///
- /// <div class="example-wrap" style="display:inline-block">
- /// <pre class="ignore" style="white-space:normal;font:inherit;">
- /// <strong>Note</strong>: This is only enabled when the Rust standard library is
- /// present.
- /// </pre>
- #[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
- fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
- self.record_debug(field, &DisplayValue(value))
- }
- /// Visit a value implementing `fmt::Debug`.
- fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug);
- }
- /// A field value of an erased type.
- ///
- /// Implementors of `Value` may call the appropriate typed recording methods on
- /// the [visitor] passed to their `record` method in order to indicate how
- /// their data should be recorded.
- ///
- /// [visitor]: Visit
- pub trait Value: crate::sealed::Sealed {
- /// Visits this value with the given `Visitor`.
- fn record(&self, key: &Field, visitor: &mut dyn Visit);
- }
- /// A `Value` which serializes using `fmt::Display`.
- ///
- /// Uses `record_debug` in the `Value` implementation to
- /// avoid an unnecessary evaluation.
- #[derive(Clone)]
- pub struct DisplayValue<T: fmt::Display>(T);
- /// A `Value` which serializes as a string using `fmt::Debug`.
- #[derive(Clone)]
- pub struct DebugValue<T: fmt::Debug>(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>
- where
- T: fmt::Display,
- {
- DisplayValue(t)
- }
- /// Wraps a type implementing `fmt::Debug` as a `Value` that can be
- /// recorded using its `Debug` implementation.
- pub fn debug<T>(t: T) -> DebugValue<T>
- where
- T: fmt::Debug,
- {
- DebugValue(t)
- }
- /// Wraps a type implementing [`Valuable`] as a `Value` that
- /// can be recorded using its `Valuable` implementation.
- ///
- /// [`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) -> valuable::Value<'_>
- where
- T: valuable::Valuable,
- {
- t.as_value()
- }
- // ===== impl Visit =====
- impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {
- fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
- self.field(field.name(), value);
- }
- }
- impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> {
- fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
- self.entry(&format_args!("{}", field), value);
- }
- }
- impl<F> Visit for F
- where
- F: FnMut(&Field, &dyn fmt::Debug),
- {
- fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
- (self)(field, value)
- }
- }
- // ===== impl Value =====
- macro_rules! impl_values {
- ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => {
- $(
- impl_value!{ $record( $( $whatever )+ ) }
- )+
- }
- }
- macro_rules! ty_to_nonzero {
- (u8) => {
- NonZeroU8
- };
- (u16) => {
- NonZeroU16
- };
- (u32) => {
- NonZeroU32
- };
- (u64) => {
- NonZeroU64
- };
- (u128) => {
- NonZeroU128
- };
- (usize) => {
- NonZeroUsize
- };
- (i8) => {
- NonZeroI8
- };
- (i16) => {
- NonZeroI16
- };
- (i32) => {
- NonZeroI32
- };
- (i64) => {
- NonZeroI64
- };
- (i128) => {
- NonZeroI128
- };
- (isize) => {
- NonZeroIsize
- };
- }
- macro_rules! impl_one_value {
- (f32, $op:expr, $record:ident) => {
- impl_one_value!(normal, f32, $op, $record);
- };
- (f64, $op:expr, $record:ident) => {
- impl_one_value!(normal, f64, $op, $record);
- };
- (bool, $op:expr, $record:ident) => {
- impl_one_value!(normal, bool, $op, $record);
- };
- ($value_ty:tt, $op:expr, $record:ident) => {
- impl_one_value!(normal, $value_ty, $op, $record);
- impl_one_value!(nonzero, $value_ty, $op, $record);
- };
- (normal, $value_ty:tt, $op:expr, $record:ident) => {
- impl $crate::sealed::Sealed for $value_ty {}
- impl $crate::field::Value for $value_ty {
- fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
- visitor.$record(key, $op(*self))
- }
- }
- };
- (nonzero, $value_ty:tt, $op:expr, $record:ident) => {
- // This `use num::*;` is reported as unused because it gets emitted
- // for every single invocation of this macro, so there are multiple `use`s.
- // All but the first are useless indeed.
- // We need this import because we can't write a path where one part is
- // the `ty_to_nonzero!($value_ty)` invocation.
- #[allow(clippy::useless_attribute, unused)]
- use num::*;
- impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
- impl $crate::field::Value for ty_to_nonzero!($value_ty) {
- fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
- visitor.$record(key, $op(self.get()))
- }
- }
- };
- }
- macro_rules! impl_value {
- ( $record:ident( $( $value_ty:tt ),+ ) ) => {
- $(
- impl_one_value!($value_ty, |this: $value_ty| this, $record);
- )+
- };
- ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
- $(
- impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
- )+
- };
- }
- // ===== impl Value =====
- impl_values! {
- record_u64(u64),
- record_u64(usize, u32, u16, u8 as u64),
- record_i64(i64),
- record_i64(isize, i32, i16, i8 as i64),
- record_bool(bool),
- record_f64(f64, f32 as f64)
- }
- impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
- impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
- fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
- self.0.record(key, visitor)
- }
- }
- impl crate::sealed::Sealed for str {}
- impl Value for str {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_str(key, self)
- }
- }
- #[cfg(feature = "std")]
- impl crate::sealed::Sealed for dyn std::error::Error + 'static {}
- #[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
- impl Value for dyn std::error::Error + 'static {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_error(key, self)
- }
- }
- #[cfg(feature = "std")]
- impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {}
- #[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
- impl Value for dyn std::error::Error + Send + 'static {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- (self as &dyn std::error::Error).record(key, visitor)
- }
- }
- #[cfg(feature = "std")]
- impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {}
- #[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
- impl Value for dyn std::error::Error + Sync + 'static {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- (self as &dyn std::error::Error).record(key, visitor)
- }
- }
- #[cfg(feature = "std")]
- impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {}
- #[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
- impl Value for dyn std::error::Error + Send + Sync + 'static {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- (self as &dyn std::error::Error).record(key, visitor)
- }
- }
- impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {}
- impl<'a, T: ?Sized> Value for &'a T
- where
- T: Value + 'a,
- {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- (*self).record(key, visitor)
- }
- }
- impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {}
- impl<'a, T: ?Sized> Value for &'a mut T
- where
- T: Value + 'a,
- {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- // Don't use `(*self).record(key, visitor)`, otherwise would
- // cause stack overflow due to `unconditional_recursion`.
- T::record(self, key, visitor)
- }
- }
- impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {}
- impl<'a> Value for fmt::Arguments<'a> {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_debug(key, self)
- }
- }
- impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {}
- impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T>
- where
- T: Value,
- {
- #[inline]
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- self.as_ref().record(key, visitor)
- }
- }
- impl fmt::Debug for dyn Value {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // We are only going to be recording the field value, so we don't
- // actually care about the field name here.
- struct NullCallsite;
- static NULL_CALLSITE: NullCallsite = NullCallsite;
- impl crate::callsite::Callsite for NullCallsite {
- fn set_interest(&self, _: crate::subscriber::Interest) {
- unreachable!("you somehow managed to register the null callsite?")
- }
- fn metadata(&self) -> &crate::Metadata<'_> {
- unreachable!("you somehow managed to access the null callsite?")
- }
- }
- static FIELD: Field = Field {
- i: 0,
- fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)),
- };
- let mut res = Ok(());
- self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| {
- res = write!(f, "{:?}", val);
- });
- res
- }
- }
- impl fmt::Display for dyn Value {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(self, f)
- }
- }
- // ===== impl DisplayValue =====
- impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {}
- impl<T> Value for DisplayValue<T>
- where
- T: fmt::Display,
- {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_debug(key, self)
- }
- }
- impl<T: fmt::Display> fmt::Debug for DisplayValue<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
- }
- impl<T: fmt::Display> fmt::Display for DisplayValue<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
- }
- // ===== impl DebugValue =====
- impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {}
- impl<T> Value for DebugValue<T>
- where
- T: fmt::Debug,
- {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_debug(key, &self.0)
- }
- }
- impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
- }
- // ===== impl ValuableValue =====
- #[cfg(all(tracing_unstable, feature = "valuable"))]
- impl crate::sealed::Sealed for valuable::Value<'_> {}
- #[cfg(all(tracing_unstable, feature = "valuable"))]
- #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
- impl Value for valuable::Value<'_> {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- 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 Value for &'_ dyn valuable::Valuable {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- visitor.record_value(key, self.as_value())
- }
- }
- impl crate::sealed::Sealed for Empty {}
- impl Value for Empty {
- #[inline]
- fn record(&self, _: &Field, _: &mut dyn Visit) {}
- }
- impl<T: Value> crate::sealed::Sealed for Option<T> {}
- impl<T: Value> Value for Option<T> {
- fn record(&self, key: &Field, visitor: &mut dyn Visit) {
- if let Some(v) = &self {
- v.record(key, visitor)
- }
- }
- }
- // ===== impl Field =====
- impl Field {
- /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
- /// which defines this field.
- ///
- /// [`Identifier`]: super::callsite::Identifier
- /// [`Callsite`]: super::callsite::Callsite
- #[inline]
- pub fn callsite(&self) -> callsite::Identifier {
- self.fields.callsite()
- }
- /// Returns a string representing the name of the field.
- pub fn name(&self) -> &'static str {
- self.fields.names[self.i]
- }
- }
- impl fmt::Display for Field {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad(self.name())
- }
- }
- impl AsRef<str> for Field {
- fn as_ref(&self) -> &str {
- self.name()
- }
- }
- impl PartialEq for Field {
- fn eq(&self, other: &Self) -> bool {
- self.callsite() == other.callsite() && self.i == other.i
- }
- }
- impl Eq for Field {}
- impl Hash for Field {
- fn hash<H>(&self, state: &mut H)
- where
- H: Hasher,
- {
- self.callsite().hash(state);
- self.i.hash(state);
- }
- }
- impl Clone for Field {
- fn clone(&self) -> Self {
- Field {
- i: self.i,
- fields: FieldSet {
- names: self.fields.names,
- callsite: self.fields.callsite(),
- },
- }
- }
- }
- // ===== impl FieldSet =====
- impl FieldSet {
- /// Constructs a new `FieldSet` with the given array of field names and callsite.
- pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self {
- Self { names, callsite }
- }
- /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
- /// which defines this set of fields..
- ///
- /// [`Identifier`]: super::callsite::Identifier
- /// [`Callsite`]: super::callsite::Callsite
- pub(crate) fn callsite(&self) -> callsite::Identifier {
- callsite::Identifier(self.callsite.0)
- }
- /// Returns the [`Field`] named `name`, or `None` if no such field exists.
- ///
- /// [`Field`]: super::Field
- pub fn field<Q: ?Sized>(&self, name: &Q) -> Option<Field>
- where
- Q: Borrow<str>,
- {
- let name = &name.borrow();
- self.names.iter().position(|f| f == name).map(|i| Field {
- i,
- fields: FieldSet {
- names: self.names,
- callsite: self.callsite(),
- },
- })
- }
- /// Returns `true` if `self` contains the given `field`.
- ///
- /// <div class="example-wrap" style="display:inline-block">
- /// <pre class="ignore" style="white-space:normal;font:inherit;">
- /// <strong>Note</strong>: If <code>field</code> shares a name with a field
- /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
- /// with a different callsite, this <code>FieldSet</code> does <em>not</em>
- /// contain it. This is so that if two separate span callsites define a field
- /// named "foo", the <code>Field</code> corresponding to "foo" for each
- /// of those callsites are not equivalent.
- /// </pre></div>
- pub fn contains(&self, field: &Field) -> bool {
- field.callsite() == self.callsite() && field.i <= self.len()
- }
- /// Returns an iterator over the `Field`s in this `FieldSet`.
- pub fn iter(&self) -> Iter {
- let idxs = 0..self.len();
- Iter {
- idxs,
- fields: FieldSet {
- names: self.names,
- callsite: self.callsite(),
- },
- }
- }
- /// Returns a new `ValueSet` with entries for this `FieldSet`'s values.
- ///
- /// Note that a `ValueSet` may not be constructed with arrays of over 32
- /// elements.
- #[doc(hidden)]
- pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v>
- where
- V: ValidLen<'v>,
- {
- ValueSet {
- fields: self,
- values: values.borrow(),
- }
- }
- /// Returns the number of fields in this `FieldSet`.
- #[inline]
- pub fn len(&self) -> usize {
- self.names.len()
- }
- /// Returns whether or not this `FieldSet` has fields.
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.names.is_empty()
- }
- }
- impl<'a> IntoIterator for &'a FieldSet {
- type IntoIter = Iter;
- type Item = Field;
- #[inline]
- fn into_iter(self) -> Self::IntoIter {
- self.iter()
- }
- }
- impl fmt::Debug for FieldSet {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("FieldSet")
- .field("names", &self.names)
- .field("callsite", &self.callsite)
- .finish()
- }
- }
- impl fmt::Display for FieldSet {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_set()
- .entries(self.names.iter().map(display))
- .finish()
- }
- }
- // ===== impl Iter =====
- impl Iterator for Iter {
- type Item = Field;
- fn next(&mut self) -> Option<Field> {
- let i = self.idxs.next()?;
- Some(Field {
- i,
- fields: FieldSet {
- names: self.fields.names,
- callsite: self.fields.callsite(),
- },
- })
- }
- }
- // ===== impl ValueSet =====
- impl<'a> ValueSet<'a> {
- /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
- /// defining the fields this `ValueSet` refers to.
- ///
- /// [`Identifier`]: super::callsite::Identifier
- /// [`Callsite`]: super::callsite::Callsite
- #[inline]
- pub fn callsite(&self) -> callsite::Identifier {
- self.fields.callsite()
- }
- /// Visits all the fields in this `ValueSet` with the provided [visitor].
- ///
- /// [visitor]: Visit
- pub fn record(&self, visitor: &mut dyn Visit) {
- let my_callsite = self.callsite();
- for (field, value) in self.values {
- if field.callsite() != my_callsite {
- continue;
- }
- if let Some(value) = value {
- value.record(field, visitor);
- }
- }
- }
- /// Returns the number of fields in this `ValueSet` that would be visited
- /// by a given [visitor] to the [`ValueSet::record()`] method.
- ///
- /// [visitor]: Visit
- /// [`ValueSet::record()`]: ValueSet::record()
- pub fn len(&self) -> usize {
- let my_callsite = self.callsite();
- self.values
- .iter()
- .filter(|(field, _)| field.callsite() == my_callsite)
- .count()
- }
- /// Returns `true` if this `ValueSet` contains a value for the given `Field`.
- pub(crate) fn contains(&self, field: &Field) -> bool {
- field.callsite() == self.callsite()
- && self
- .values
- .iter()
- .any(|(key, val)| *key == field && val.is_some())
- }
- /// Returns true if this `ValueSet` contains _no_ values.
- pub fn is_empty(&self) -> bool {
- let my_callsite = self.callsite();
- self.values
- .iter()
- .all(|(key, val)| val.is_none() || key.callsite() != my_callsite)
- }
- pub(crate) fn field_set(&self) -> &FieldSet {
- self.fields
- }
- }
- impl<'a> fmt::Debug for ValueSet<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.values
- .iter()
- .fold(&mut f.debug_struct("ValueSet"), |dbg, (key, v)| {
- if let Some(val) = v {
- val.record(key, dbg);
- }
- dbg
- })
- .field("callsite", &self.callsite())
- .finish()
- }
- }
- impl<'a> fmt::Display for ValueSet<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.values
- .iter()
- .fold(&mut f.debug_map(), |dbg, (key, v)| {
- if let Some(val) = v {
- val.record(key, dbg);
- }
- dbg
- })
- .finish()
- }
- }
- // ===== impl ValidLen =====
- mod private {
- use super::*;
- /// Marker trait implemented by arrays which are of valid length to
- /// construct a `ValueSet`.
- ///
- /// `ValueSet`s may only be constructed from arrays containing 32 or fewer
- /// elements, to ensure the array is small enough to always be allocated on the
- /// stack. This trait is only implemented by arrays of an appropriate length,
- /// ensuring that the correct size arrays are used at compile-time.
- pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {}
- }
- macro_rules! impl_valid_len {
- ( $( $len:tt ),+ ) => {
- $(
- impl<'a> private::ValidLen<'a> for
- [(&'a Field, Option<&'a (dyn Value + 'a)>); $len] {}
- )+
- }
- }
- impl_valid_len! {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
- }
- #[cfg(test)]
- mod test {
- use super::*;
- use crate::metadata::{Kind, Level, Metadata};
- use crate::stdlib::{borrow::ToOwned, string::String};
- struct TestCallsite1;
- static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1;
- static TEST_META_1: Metadata<'static> = metadata! {
- name: "field_test1",
- target: module_path!(),
- level: Level::INFO,
- fields: &["foo", "bar", "baz"],
- callsite: &TEST_CALLSITE_1,
- kind: Kind::SPAN,
- };
- impl crate::callsite::Callsite for TestCallsite1 {
- fn set_interest(&self, _: crate::subscriber::Interest) {
- unimplemented!()
- }
- fn metadata(&self) -> &Metadata<'_> {
- &TEST_META_1
- }
- }
- struct TestCallsite2;
- static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2;
- static TEST_META_2: Metadata<'static> = metadata! {
- name: "field_test2",
- target: module_path!(),
- level: Level::INFO,
- fields: &["foo", "bar", "baz"],
- callsite: &TEST_CALLSITE_2,
- kind: Kind::SPAN,
- };
- impl crate::callsite::Callsite for TestCallsite2 {
- fn set_interest(&self, _: crate::subscriber::Interest) {
- unimplemented!()
- }
- fn metadata(&self) -> &Metadata<'_> {
- &TEST_META_2
- }
- }
- #[test]
- fn value_set_with_no_values_is_empty() {
- let fields = TEST_META_1.fields();
- let values = &[
- (&fields.field("foo").unwrap(), None),
- (&fields.field("bar").unwrap(), None),
- (&fields.field("baz").unwrap(), None),
- ];
- let valueset = fields.value_set(values);
- assert!(valueset.is_empty());
- }
- #[test]
- fn empty_value_set_is_empty() {
- let fields = TEST_META_1.fields();
- let valueset = fields.value_set(&[]);
- assert!(valueset.is_empty());
- }
- #[test]
- fn value_sets_with_fields_from_other_callsites_are_empty() {
- let fields = TEST_META_1.fields();
- let values = &[
- (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
- (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
- (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
- ];
- let valueset = TEST_META_2.fields().value_set(values);
- assert!(valueset.is_empty())
- }
- #[test]
- fn sparse_value_sets_are_not_empty() {
- let fields = TEST_META_1.fields();
- let values = &[
- (&fields.field("foo").unwrap(), None),
- (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
- (&fields.field("baz").unwrap(), None),
- ];
- let valueset = fields.value_set(values);
- assert!(!valueset.is_empty());
- }
- #[test]
- fn fields_from_other_callsets_are_skipped() {
- let fields = TEST_META_1.fields();
- let values = &[
- (&fields.field("foo").unwrap(), None),
- (
- &TEST_META_2.fields().field("bar").unwrap(),
- Some(&57 as &dyn Value),
- ),
- (&fields.field("baz").unwrap(), None),
- ];
- struct MyVisitor;
- impl Visit for MyVisitor {
- fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
- assert_eq!(field.callsite(), TEST_META_1.callsite())
- }
- }
- let valueset = fields.value_set(values);
- 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();
- let values = &[
- (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
- (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
- (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
- ];
- let valueset = fields.value_set(values);
- let mut result = String::new();
- valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
- use crate::stdlib::fmt::Write;
- write!(&mut result, "{:?}", value).unwrap();
- });
- assert_eq!(result, "123".to_owned());
- }
- #[test]
- #[cfg(feature = "std")]
- fn record_error() {
- let fields = TEST_META_1.fields();
- let err: Box<dyn std::error::Error + Send + Sync + 'static> =
- std::io::Error::new(std::io::ErrorKind::Other, "lol").into();
- let values = &[
- (&fields.field("foo").unwrap(), Some(&err as &dyn Value)),
- (&fields.field("bar").unwrap(), Some(&Empty as &dyn Value)),
- (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
- ];
- let valueset = fields.value_set(values);
- let mut result = String::new();
- valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
- use core::fmt::Write;
- write!(&mut result, "{:?}", value).unwrap();
- });
- assert_eq!(result, format!("{}", err));
- }
- }
|