diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/tracing-subscriber-0.3.3/src/fmt/format/pretty.rs | 415 | ||||
-rw-r--r-- | vendor/tracing-subscriber-0.3.3/src/fmt/time/time_crate.rs | 276 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/fmt_layer.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/fmt_layer.rs) | 321 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/format/json.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs) | 175 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/format/mod.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/format/mod.rs) | 459 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/mod.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/mod.rs) | 392 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/time/datetime.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/time/datetime.rs) | 0 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/time/mod.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/time/mod.rs) | 8 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/writer.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/writer.rs) | 30 |
9 files changed, 1116 insertions, 960 deletions
diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/format/pretty.rs b/vendor/tracing-subscriber-0.3.3/src/fmt/format/pretty.rs deleted file mode 100644 index 3e47e2d93..000000000 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/format/pretty.rs +++ /dev/null @@ -1,415 +0,0 @@ -use super::*; -use crate::{ - field::{VisitFmt, VisitOutput}, - fmt::fmt_layer::{FmtContext, FormattedFields}, - registry::LookupSpan, -}; - -use std::fmt; -use tracing_core::{ - field::{self, Field}, - Event, Level, Subscriber, -}; - -#[cfg(feature = "tracing-log")] -use tracing_log::NormalizeEvent; - -use ansi_term::{Colour, Style}; - -/// An excessively pretty, human-readable event formatter. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Pretty { - display_location: bool, -} - -/// The [visitor] produced by [`Pretty`]'s [`MakeVisitor`] implementation. -/// -/// [visitor]: field::Visit -/// [`MakeVisitor`]: crate::field::MakeVisitor -#[derive(Debug)] -pub struct PrettyVisitor<'a> { - writer: Writer<'a>, - is_empty: bool, - style: Style, - result: fmt::Result, -} - -/// An excessively pretty, human-readable [`MakeVisitor`] implementation. -/// -/// [`MakeVisitor`]: crate::field::MakeVisitor -#[derive(Debug)] -pub struct PrettyFields { - /// A value to override the provided `Writer`'s ANSI formatting - /// configuration. - /// - /// If this is `Some`, we override the `Writer`'s ANSI setting. This is - /// necessary in order to continue supporting the deprecated - /// `PrettyFields::with_ansi` method. If it is `None`, we don't override the - /// ANSI formatting configuration (because the deprecated method was not - /// called). - // TODO: when `PrettyFields::with_ansi` is removed, we can get rid - // of this entirely. - ansi: Option<bool>, -} - -// === impl Pretty === - -impl Default for Pretty { - fn default() -> Self { - Self { - display_location: true, - } - } -} - -impl Pretty { - fn style_for(level: &Level) -> Style { - match *level { - Level::TRACE => Style::new().fg(Colour::Purple), - Level::DEBUG => Style::new().fg(Colour::Blue), - Level::INFO => Style::new().fg(Colour::Green), - Level::WARN => Style::new().fg(Colour::Yellow), - Level::ERROR => Style::new().fg(Colour::Red), - } - } - - /// Sets whether the event's source code location is displayed. - /// - /// This defaults to `true`. - pub fn with_source_location(self, display_location: bool) -> Self { - Self { - display_location, - ..self - } - } -} - -impl<T> Format<Pretty, T> { - /// Sets whether or not the source code location from which an event - /// originated is displayed. - /// - /// This defaults to `true`. - pub fn with_source_location(mut self, display_location: bool) -> Self { - self.format = self.format.with_source_location(display_location); - self - } -} - -impl<C, N, T> FormatEvent<C, N> for Format<Pretty, T> -where - C: Subscriber + for<'a> LookupSpan<'a>, - N: for<'a> FormatFields<'a> + 'static, - T: FormatTime, -{ - fn format_event( - &self, - ctx: &FmtContext<'_, C, N>, - mut writer: Writer<'_>, - event: &Event<'_>, - ) -> fmt::Result { - #[cfg(feature = "tracing-log")] - let normalized_meta = event.normalized_metadata(); - #[cfg(feature = "tracing-log")] - let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); - #[cfg(not(feature = "tracing-log"))] - let meta = event.metadata(); - write!(&mut writer, " ")?; - - // if the `Format` struct *also* has an ANSI color configuration, - // override the writer...the API for configuring ANSI color codes on the - // `Format` struct is deprecated, but we still need to honor those - // configurations. - if let Some(ansi) = self.ansi { - writer = writer.with_ansi(ansi); - } - - self.format_timestamp(&mut writer)?; - - let style = if self.display_level && writer.has_ansi_escapes() { - Pretty::style_for(meta.level()) - } else { - Style::new() - }; - - if self.display_level { - write!( - writer, - "{} ", - super::FmtLevel::new(meta.level(), writer.has_ansi_escapes()) - )?; - } - - if self.display_target { - let target_style = if writer.has_ansi_escapes() { - style.bold() - } else { - style - }; - write!( - writer, - "{}{}{}: ", - target_style.prefix(), - meta.target(), - target_style.infix(style) - )?; - } - let mut v = PrettyVisitor::new(writer.by_ref(), true).with_style(style); - event.record(&mut v); - v.finish()?; - writer.write_char('\n')?; - - let dimmed = if writer.has_ansi_escapes() { - Style::new().dimmed().italic() - } else { - Style::new() - }; - let thread = self.display_thread_name || self.display_thread_id; - if let (true, Some(file), Some(line)) = - (self.format.display_location, meta.file(), meta.line()) - { - write!( - writer, - " {} {}:{}{}", - dimmed.paint("at"), - file, - line, - dimmed.paint(if thread { " " } else { "\n" }) - )?; - } else if thread { - write!(writer, " ")?; - } - - if thread { - write!(writer, "{} ", dimmed.paint("on"))?; - let thread = std::thread::current(); - if self.display_thread_name { - if let Some(name) = thread.name() { - write!(writer, "{}", name)?; - if self.display_thread_id { - write!(writer, " ({:?})", thread.id())?; - } - } else if !self.display_thread_id { - write!(writer, " {:?}", thread.id())?; - } - } else if self.display_thread_id { - write!(writer, " {:?}", thread.id())?; - } - writer.write_char('\n')?; - } - - let bold = writer.bold(); - let span = event - .parent() - .and_then(|id| ctx.span(id)) - .or_else(|| ctx.lookup_current()); - - let scope = span.into_iter().flat_map(|span| span.scope()); - - for span in scope { - let meta = span.metadata(); - if self.display_target { - write!( - writer, - " {} {}::{}", - dimmed.paint("in"), - meta.target(), - bold.paint(meta.name()), - )?; - } else { - write!( - writer, - " {} {}", - dimmed.paint("in"), - bold.paint(meta.name()), - )?; - } - - let ext = span.extensions(); - let fields = &ext - .get::<FormattedFields<N>>() - .expect("Unable to find FormattedFields in extensions; this is a bug"); - if !fields.is_empty() { - write!(writer, " {} {}", dimmed.paint("with"), fields)?; - } - writer.write_char('\n')?; - } - - writer.write_char('\n') - } -} - -impl<'writer> FormatFields<'writer> for Pretty { - fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result { - let mut v = PrettyVisitor::new(writer, false); - fields.record(&mut v); - v.finish() - } - - fn add_fields( - &self, - current: &'writer mut FormattedFields<Self>, - fields: &span::Record<'_>, - ) -> fmt::Result { - let empty = current.is_empty(); - let writer = current.as_writer(); - let mut v = PrettyVisitor::new(writer, empty); - fields.record(&mut v); - v.finish() - } -} - -// === impl PrettyFields === - -impl Default for PrettyFields { - fn default() -> Self { - Self::new() - } -} - -impl PrettyFields { - /// Returns a new default [`PrettyFields`] implementation. - pub fn new() -> Self { - // By default, don't override the `Writer`'s ANSI colors - // configuration. We'll only do this if the user calls the - // deprecated `PrettyFields::with_ansi` method. - Self { ansi: None } - } - - /// Enable ANSI encoding for formatted fields. - #[deprecated( - since = "0.3.3", - note = "Use `fmt::Subscriber::with_ansi` or `fmt::Layer::with_ansi` instead." - )] - pub fn with_ansi(self, ansi: bool) -> Self { - Self { - ansi: Some(ansi), - ..self - } - } -} - -impl<'a> MakeVisitor<Writer<'a>> for PrettyFields { - type Visitor = PrettyVisitor<'a>; - - #[inline] - fn make_visitor(&self, mut target: Writer<'a>) -> Self::Visitor { - if let Some(ansi) = self.ansi { - target = target.with_ansi(ansi); - } - PrettyVisitor::new(target, true) - } -} - -// === impl PrettyVisitor === - -impl<'a> PrettyVisitor<'a> { - /// Returns a new default visitor that formats to the provided `writer`. - /// - /// # Arguments - /// - `writer`: the writer to format to. - /// - `is_empty`: whether or not any fields have been previously written to - /// that writer. - pub fn new(writer: Writer<'a>, is_empty: bool) -> Self { - Self { - writer, - is_empty, - style: Style::default(), - result: Ok(()), - } - } - - pub(crate) fn with_style(self, style: Style) -> Self { - Self { style, ..self } - } - - fn write_padded(&mut self, value: &impl fmt::Debug) { - let padding = if self.is_empty { - self.is_empty = false; - "" - } else { - ", " - }; - self.result = write!(self.writer, "{}{:?}", padding, value); - } - - fn bold(&self) -> Style { - if self.writer.has_ansi_escapes() { - self.style.bold() - } else { - Style::new() - } - } -} - -impl<'a> field::Visit for PrettyVisitor<'a> { - fn record_str(&mut self, field: &Field, value: &str) { - if self.result.is_err() { - return; - } - - if field.name() == "message" { - self.record_debug(field, &format_args!("{}", value)) - } else { - self.record_debug(field, &value) - } - } - - fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) { - if let Some(source) = value.source() { - let bold = self.bold(); - self.record_debug( - field, - &format_args!( - "{}, {}{}.sources{}: {}", - value, - bold.prefix(), - field, - bold.infix(self.style), - ErrorSourceList(source), - ), - ) - } else { - self.record_debug(field, &format_args!("{}", value)) - } - } - - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - if self.result.is_err() { - return; - } - let bold = self.bold(); - match field.name() { - "message" => self.write_padded(&format_args!("{}{:?}", self.style.prefix(), value,)), - // Skip fields that are actually log metadata that have already been handled - #[cfg(feature = "tracing-log")] - name if name.starts_with("log.") => self.result = Ok(()), - name if name.starts_with("r#") => self.write_padded(&format_args!( - "{}{}{}: {:?}", - bold.prefix(), - &name[2..], - bold.infix(self.style), - value - )), - name => self.write_padded(&format_args!( - "{}{}{}: {:?}", - bold.prefix(), - name, - bold.infix(self.style), - value - )), - }; - } -} - -impl<'a> VisitOutput<fmt::Result> for PrettyVisitor<'a> { - fn finish(mut self) -> fmt::Result { - write!(&mut self.writer, "{}", self.style.suffix())?; - self.result - } -} - -impl<'a> VisitFmt for PrettyVisitor<'a> { - fn writer(&mut self) -> &mut dyn fmt::Write { - &mut self.writer - } -} diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/time/time_crate.rs b/vendor/tracing-subscriber-0.3.3/src/fmt/time/time_crate.rs deleted file mode 100644 index 64d274365..000000000 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/time/time_crate.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::fmt::{format::Writer, time::FormatTime, writer::WriteAdaptor}; -use std::fmt; -use time::{format_description::well_known, formatting::Formattable, OffsetDateTime}; - -/// Formats the current [local time] using a [formatter] from the [`time` crate]. -/// -/// To format the current [UTC time] instead, use the [`UtcTime`] type. -/// -/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local -/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc -/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html -/// [`time` crate]: https://docs.rs/time/0.3/time/ -#[derive(Clone, Debug)] -#[cfg_attr(docsrs, doc(cfg(all(feature = "time", feature = "local-time"))))] -#[cfg(feature = "local-time")] -pub struct LocalTime<F> { - format: F, -} - -/// Formats the current [UTC time] using a [formatter] from the [`time` crate]. -/// -/// To format the current [local time] instead, use the [`LocalTime`] type. -/// -/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local -/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc -/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html -/// [`time` crate]: https://docs.rs/time/0.3/time/ -#[cfg_attr(docsrs, doc(cfg(feature = "time")))] -#[derive(Clone, Debug)] -pub struct UtcTime<F> { - format: F, -} - -// === impl LocalTime === - -#[cfg(feature = "local-time")] -impl LocalTime<well_known::Rfc3339> { - /// Returns a formatter that formats the current [local time] in the - /// [RFC 3339] format (a subset of the [ISO 8601] timestamp format). - /// - /// # Examples - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time}; - /// - /// let collector = tracing_subscriber::fmt() - /// .with_timer(time::LocalTime::rfc_3339()); - /// # drop(collector); - /// ``` - /// - /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local - /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339 - /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601 - pub fn rfc_3339() -> Self { - Self::new(well_known::Rfc3339) - } -} - -#[cfg(feature = "local-time")] -impl<F: Formattable> LocalTime<F> { - /// Returns a formatter that formats the current [local time] using the - /// [`time` crate] with the provided provided format. The format may be any - /// type that implements the [`Formattable`] trait. - /// - /// Typically, the format will be a format description string, or one of the - /// `time` crate's [well-known formats]. - /// - /// If the format description is statically known, then the - /// [`format_description!`] macro should be used. This is identical to the - /// [`time::format_description::parse`] method, but runs at compile-time, - /// throwing an error if the format description is invalid. If the desired format - /// is not known statically (e.g., a user is providing a format string), then the - /// [`time::format_description::parse`] method should be used. Note that this - /// method is fallible. - /// - /// See the [`time` book] for details on the format description syntax. - /// - /// # Examples - /// - /// Using the [`format_description!`] macro: - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::LocalTime}; - /// use time::macros::format_description; - /// - /// let timer = LocalTime::new(format_description!("[hour]:[minute]:[second]")); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// Using [`time::format_description::parse`]: - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::LocalTime}; - /// - /// let time_format = time::format_description::parse("[hour]:[minute]:[second]") - /// .expect("format string should be valid!"); - /// let timer = LocalTime::new(time_format); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// Using the [`format_description!`] macro requires enabling the `time` - /// crate's "macros" feature flag. - /// - /// Using a [well-known format][well-known formats] (this is equivalent to - /// [`LocalTime::rfc_3339`]): - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::LocalTime}; - /// - /// let timer = LocalTime::new(time::format_description::well_known::Rfc3339); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// [local time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_local - /// [`time` crate]: https://docs.rs/time/0.3/time/ - /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html - /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html - /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html - /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html - /// [`time` book]: https://time-rs.github.io/book/api/format-description.html - pub fn new(format: F) -> Self { - Self { format } - } -} - -#[cfg(feature = "local-time")] -impl<F> FormatTime for LocalTime<F> -where - F: Formattable, -{ - fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { - let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?; - format_datetime(now, w, &self.format) - } -} - -#[cfg(feature = "local-time")] -impl<F> Default for LocalTime<F> -where - F: Formattable + Default, -{ - fn default() -> Self { - Self::new(F::default()) - } -} - -// === impl UtcTime === - -impl UtcTime<well_known::Rfc3339> { - /// Returns a formatter that formats the current [UTC time] in the - /// [RFC 3339] format, which is a subset of the [ISO 8601] timestamp format. - /// - /// # Examples - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time}; - /// - /// let collector = tracing_subscriber::fmt() - /// .with_timer(time::UtcTime::rfc_3339()); - /// # drop(collector); - /// ``` - /// - /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc - /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339 - /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601 - pub fn rfc_3339() -> Self { - Self::new(well_known::Rfc3339) - } -} - -impl<F: Formattable> UtcTime<F> { - /// Returns a formatter that formats the current [UTC time] using the - /// [`time` crate], with the provided provided format. The format may be any - /// type that implements the [`Formattable`] trait. - /// - /// Typically, the format will be a format description string, or one of the - /// `time` crate's [well-known formats]. - /// - /// If the format description is statically known, then the - /// [`format_description!`] macro should be used. This is identical to the - /// [`time::format_description::parse`] method, but runs at compile-time, - /// failing an error if the format description is invalid. If the desired format - /// is not known statically (e.g., a user is providing a format string), then the - /// [`time::format_description::parse`] method should be used. Note that this - /// method is fallible. - /// - /// See the [`time` book] for details on the format description syntax. - /// - /// # Examples - /// - /// Using the [`format_description!`] macro: - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::UtcTime}; - /// use time::macros::format_description; - /// - /// let timer = UtcTime::new(format_description!("[hour]:[minute]:[second]")); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// Using the [`format_description!`] macro requires enabling the `time` - /// crate's "macros" feature flag. - /// - /// Using [`time::format_description::parse`]: - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::UtcTime}; - /// - /// let time_format = time::format_description::parse("[hour]:[minute]:[second]") - /// .expect("format string should be valid!"); - /// let timer = UtcTime::new(time_format); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// Using a [well-known format][well-known formats] (this is equivalent to - /// [`UtcTime::rfc_3339`]): - /// - /// ``` - /// use tracing_subscriber::fmt::{self, time::UtcTime}; - /// - /// let timer = UtcTime::new(time::format_description::well_known::Rfc3339); - /// let collector = tracing_subscriber::fmt() - /// .with_timer(timer); - /// # drop(collector); - /// ``` - /// - /// [UTC time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_utc - /// [`time` crate]: https://docs.rs/time/0.3/time/ - /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html - /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html - /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html - /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html - /// [`time` book]: https://time-rs.github.io/book/api/format-description.html - pub fn new(format: F) -> Self { - Self { format } - } -} - -impl<F> FormatTime for UtcTime<F> -where - F: Formattable, -{ - fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { - format_datetime(OffsetDateTime::now_utc(), w, &self.format) - } -} - -impl<F> Default for UtcTime<F> -where - F: Formattable + Default, -{ - fn default() -> Self { - Self::new(F::default()) - } -} - -fn format_datetime( - now: OffsetDateTime, - into: &mut Writer<'_>, - fmt: &impl Formattable, -) -> fmt::Result { - let mut into = WriteAdaptor::new(into); - now.format_into(&mut into, fmt) - .map_err(|_| fmt::Error) - .map(|_| ()) -} diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/fmt_layer.rs b/vendor/tracing-subscriber/src/fmt/fmt_layer.rs index 0e0d5e0eb..6e4e2ac0b 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/fmt_layer.rs +++ b/vendor/tracing-subscriber/src/fmt/fmt_layer.rs @@ -56,7 +56,7 @@ use tracing_core::{ /// # tracing::subscriber::set_global_default(subscriber).unwrap(); /// ``` /// -/// [`Layer`]: ../layer/trait.Layer.html +/// [`Layer`]: super::layer::Layer #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] #[derive(Debug)] pub struct Layer< @@ -70,11 +70,12 @@ pub struct Layer< fmt_event: E, fmt_span: format::FmtSpanConfig, is_ansi: bool, - _inner: PhantomData<S>, + log_internal_errors: bool, + _inner: PhantomData<fn(S)>, } impl<S> Layer<S> { - /// Returns a new [`Layer`](struct.Layer.html) with the default configuration. + /// Returns a new [`Layer`][self::Layer] with the default configuration. pub fn new() -> Self { Self::default() } @@ -87,8 +88,8 @@ where N: for<'writer> FormatFields<'writer> + 'static, W: for<'writer> MakeWriter<'writer> + 'static, { - /// Sets the [event formatter][`FormatEvent`] that the layer will use to - /// format events. + /// Sets the [event formatter][`FormatEvent`] that the layer being built will + /// use to format events. /// /// The event formatter may be any type implementing the [`FormatEvent`] /// trait, which is implemented for all functions taking a [`FmtContext`], a @@ -108,7 +109,7 @@ where /// ``` /// [`FormatEvent`]: format::FormatEvent /// [`Event`]: tracing::Event - /// [`Writer`]: crate::format::Writer + /// [`Writer`]: format::Writer pub fn event_format<E2>(self, e: E2) -> Layer<S, N, E2, W> where E2: FormatEvent<S, N> + 'static, @@ -119,6 +120,37 @@ where fmt_span: self.fmt_span, make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, + _inner: self._inner, + } + } + + /// Updates the event formatter by applying a function to the existing event formatter. + /// + /// This sets the event formatter that the layer being built will use to record fields. + /// + /// # Examples + /// + /// Updating an event formatter: + /// + /// ```rust + /// let layer = tracing_subscriber::fmt::layer() + /// .map_event_format(|e| e.compact()); + /// # // this is necessary for type inference. + /// # use tracing_subscriber::Layer as _; + /// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default()); + /// ``` + pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> Layer<S, N, E2, W> + where + E2: FormatEvent<S, N> + 'static, + { + Layer { + fmt_fields: self.fmt_fields, + fmt_event: f(self.fmt_event), + fmt_span: self.fmt_span, + make_writer: self.make_writer, + is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -126,7 +158,7 @@ where // This needs to be a seperate impl block because they place different bounds on the type parameters. impl<S, N, E, W> Layer<S, N, E, W> { - /// Sets the [`MakeWriter`] that the [`Layer`] being built will use to write events. + /// Sets the [`MakeWriter`] that the layer being built will use to write events. /// /// # Examples /// @@ -142,9 +174,6 @@ impl<S, N, E, W> Layer<S, N, E, W> { /// # use tracing_subscriber::Layer as _; /// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default()); /// ``` - /// - /// [`MakeWriter`]: ../fmt/trait.MakeWriter.html - /// [`Layer`]: ../layer/trait.Layer.html pub fn with_writer<W2>(self, make_writer: W2) -> Layer<S, N, E, W2> where W2: for<'writer> MakeWriter<'writer> + 'static, @@ -154,12 +183,63 @@ impl<S, N, E, W> Layer<S, N, E, W> { fmt_event: self.fmt_event, fmt_span: self.fmt_span, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, make_writer, _inner: self._inner, } } - /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in + /// Borrows the [writer] for this [`Layer`]. + /// + /// [writer]: MakeWriter + pub fn writer(&self) -> &W { + &self.make_writer + } + + /// Mutably borrows the [writer] for this [`Layer`]. + /// + /// This method is primarily expected to be used with the + /// [`reload::Handle::modify`](crate::reload::Handle::modify) method. + /// + /// # Examples + /// + /// ``` + /// # use tracing::info; + /// # use tracing_subscriber::{fmt,reload,Registry,prelude::*}; + /// # fn non_blocking<T: std::io::Write>(writer: T) -> (fn() -> std::io::Stdout) { + /// # std::io::stdout + /// # } + /// # fn main() { + /// let layer = fmt::layer().with_writer(non_blocking(std::io::stderr())); + /// let (layer, reload_handle) = reload::Layer::new(layer); + /// # + /// # // specifying the Registry type is required + /// # let _: &reload::Handle<fmt::Layer<Registry, _, _, _>, Registry> = &reload_handle; + /// # + /// info!("This will be logged to stderr"); + /// reload_handle.modify(|layer| *layer.writer_mut() = non_blocking(std::io::stdout())); + /// info!("This will be logged to stdout"); + /// # } + /// ``` + /// + /// [writer]: MakeWriter + pub fn writer_mut(&mut self) -> &mut W { + &mut self.make_writer + } + + /// Sets whether this layer should use ANSI terminal formatting + /// escape codes (such as colors). + /// + /// This method is primarily expected to be used with the + /// [`reload::Handle::modify`](crate::reload::Handle::modify) method when changing + /// the writer. + #[cfg(feature = "ansi")] + #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))] + pub fn set_ansi(&mut self, ansi: bool) { + self.is_ansi = ansi; + } + + /// Configures the layer to support [`libtest`'s output capturing][capturing] when used in /// unit tests. /// /// See [`TestWriter`] for additional details. @@ -180,13 +260,14 @@ impl<S, N, E, W> Layer<S, N, E, W> { /// ``` /// [capturing]: /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output - /// [`TestWriter`]: writer/struct.TestWriter.html + /// [`TestWriter`]: super::writer::TestWriter pub fn with_test_writer(self) -> Layer<S, N, E, TestWriter> { Layer { fmt_fields: self.fmt_fields, fmt_event: self.fmt_event, fmt_span: self.fmt_span, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, make_writer: TestWriter::default(), _inner: self._inner, } @@ -201,6 +282,58 @@ impl<S, N, E, W> Layer<S, N, E, W> { ..self } } + + /// Sets whether to write errors from [`FormatEvent`] to the writer. + /// Defaults to true. + /// + /// By default, `fmt::Layer` will write any `FormatEvent`-internal errors to + /// the writer. These errors are unlikely and will only occur if there is a + /// bug in the `FormatEvent` implementation or its dependencies. + /// + /// If writing to the writer fails, the error message is printed to stderr + /// as a fallback. + /// + /// [`FormatEvent`]: crate::fmt::FormatEvent + pub fn log_internal_errors(self, log_internal_errors: bool) -> Self { + Self { + log_internal_errors, + ..self + } + } + + /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`]. + /// + /// This sets the [`MakeWriter`] that the layer being built will use to write events. + /// + /// # Examples + /// + /// Redirect output to stderr if level is <= WARN: + /// + /// ```rust + /// use tracing::Level; + /// use tracing_subscriber::fmt::{self, writer::MakeWriterExt}; + /// + /// let stderr = std::io::stderr.with_max_level(Level::WARN); + /// let layer = fmt::layer() + /// .map_writer(move |w| stderr.or_else(w)); + /// # // this is necessary for type inference. + /// # use tracing_subscriber::Layer as _; + /// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default()); + /// ``` + pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Layer<S, N, E, W2> + where + W2: for<'writer> MakeWriter<'writer> + 'static, + { + Layer { + fmt_fields: self.fmt_fields, + fmt_event: self.fmt_event, + fmt_span: self.fmt_span, + is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, + make_writer: f(self.make_writer), + _inner: self._inner, + } + } } impl<S, N, L, T, W> Layer<S, N, format::Format<L, T>, W> @@ -228,6 +361,7 @@ where fmt_span: self.fmt_span, make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -240,6 +374,7 @@ where fmt_span: self.fmt_span.without_time(), make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -284,7 +419,7 @@ where /// `Layer`s added to this subscriber. /// /// [lifecycle]: https://docs.rs/tracing/latest/tracing/span/index.html#the-span-lifecycle - /// [time]: #method.without_time + /// [time]: Layer::without_time() pub fn with_span_events(self, kind: FmtSpan) -> Self { Layer { fmt_span: self.fmt_span.with_kind(kind), @@ -299,6 +434,30 @@ where ..self } } + /// Sets whether or not an event's [source code file path][file] is + /// displayed. + /// + /// [file]: tracing_core::Metadata::file + pub fn with_file(self, display_filename: bool) -> Layer<S, N, format::Format<L, T>, W> { + Layer { + fmt_event: self.fmt_event.with_file(display_filename), + ..self + } + } + + /// Sets whether or not an event's [source code line number][line] is + /// displayed. + /// + /// [line]: tracing_core::Metadata::line + pub fn with_line_number( + self, + display_line_number: bool, + ) -> Layer<S, N, format::Format<L, T>, W> { + Layer { + fmt_event: self.fmt_event.with_line_number(display_line_number), + ..self + } + } /// Sets whether or not an event's level is displayed. pub fn with_level(self, display_level: bool) -> Layer<S, N, format::Format<L, T>, W> { @@ -309,9 +468,9 @@ where } /// Sets whether or not the [thread ID] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html + /// [thread ID]: std::thread::ThreadId pub fn with_thread_ids(self, display_thread_ids: bool) -> Layer<S, N, format::Format<L, T>, W> { Layer { fmt_event: self.fmt_event.with_thread_ids(display_thread_ids), @@ -320,9 +479,9 @@ where } /// Sets whether or not the [name] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads + /// [name]: std::thread#naming-threads pub fn with_thread_names( self, display_thread_names: bool, @@ -333,7 +492,7 @@ where } } - /// Sets the layer being built to use a [less verbose formatter](../fmt/format/struct.Compact.html). + /// Sets the layer being built to use a [less verbose formatter][super::format::Compact]. pub fn compact(self) -> Layer<S, N, format::Format<format::Compact, T>, W> where N: for<'writer> FormatFields<'writer> + 'static, @@ -344,6 +503,7 @@ where fmt_span: self.fmt_span, make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -358,11 +518,12 @@ where fmt_span: self.fmt_span, make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } - /// Sets the layer being built to use a [JSON formatter](../fmt/format/struct.Json.html). + /// Sets the layer being built to use a [JSON formatter][super::format::Json]. /// /// The full format includes fields from all entered spans. /// @@ -377,7 +538,7 @@ where /// - [`Layer::flatten_event`] can be used to enable flattening event fields into the root /// object. /// - /// [`Layer::flatten_event`]: #method.flatten_event + /// [`Layer::flatten_event`]: Layer::flatten_event() #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn json(self) -> Layer<S, format::JsonFields, format::Format<format::Json, T>, W> { @@ -388,6 +549,7 @@ where make_writer: self.make_writer, // always disable ANSI escapes in JSON mode! is_ansi: false, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -398,7 +560,7 @@ where impl<S, T, W> Layer<S, format::JsonFields, format::Format<format::Json, T>, W> { /// Sets the JSON layer being built to flatten event metadata. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::format::Json] pub fn flatten_event( self, flatten_event: bool, @@ -413,7 +575,7 @@ impl<S, T, W> Layer<S, format::JsonFields, format::Format<format::Json, T>, W> { /// Sets whether or not the formatter will include the current span in /// formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::format::Json] pub fn with_current_span( self, display_current_span: bool, @@ -428,7 +590,7 @@ impl<S, T, W> Layer<S, format::JsonFields, format::Format<format::Json, T>, W> { /// Sets whether or not the formatter will include a list (from root to leaf) /// of all currently entered spans in formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::format::Json] pub fn with_span_list( self, display_span_list: bool, @@ -454,6 +616,38 @@ impl<S, N, E, W> Layer<S, N, E, W> { fmt_span: self.fmt_span, make_writer: self.make_writer, is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, + _inner: self._inner, + } + } + + /// Updates the field formatter by applying a function to the existing field formatter. + /// + /// This sets the field formatter that the layer being built will use to record fields. + /// + /// # Examples + /// + /// Updating a field formatter: + /// + /// ```rust + /// use tracing_subscriber::field::MakeExt; + /// let layer = tracing_subscriber::fmt::layer() + /// .map_fmt_fields(|f| f.debug_alt()); + /// # // this is necessary for type inference. + /// # use tracing_subscriber::Layer as _; + /// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default()); + /// ``` + pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> Layer<S, N2, E, W> + where + N2: for<'writer> FormatFields<'writer> + 'static, + { + Layer { + fmt_event: self.fmt_event, + fmt_fields: f(self.fmt_fields), + fmt_span: self.fmt_span, + make_writer: self.make_writer, + is_ansi: self.is_ansi, + log_internal_errors: self.log_internal_errors, _inner: self._inner, } } @@ -467,6 +661,7 @@ impl<S> Default for Layer<S> { fmt_span: format::FmtSpanConfig::default(), make_writer: io::stdout, is_ansi: cfg!(feature = "ansi"), + log_internal_errors: false, _inner: PhantomData, } } @@ -497,7 +692,7 @@ where /// formatters are in use, each can store its own formatted representation /// without conflicting. /// -/// [extensions]: ../registry/struct.Extensions.html +/// [extensions]: crate::registry::Extensions #[derive(Default)] pub struct FormattedFields<E: ?Sized> { _format_fields: PhantomData<fn(E)>, @@ -586,6 +781,11 @@ where { fields.was_ansi = self.is_ansi; extensions.insert(fields); + } else { + eprintln!( + "[tracing-subscriber] Unable to format the following event, ignoring: {:?}", + attrs + ); } } @@ -732,7 +932,20 @@ where .is_ok() { let mut writer = self.make_writer.make_writer_for(event.metadata()); - let _ = io::Write::write_all(&mut writer, buf.as_bytes()); + let res = io::Write::write_all(&mut writer, buf.as_bytes()); + if self.log_internal_errors { + if let Err(e) = res { + eprintln!("[tracing-subscriber] Unable to write an event to the Writer for this Subscriber! Error: {}\n", e); + } + } + } else if self.log_internal_errors { + let err_msg = format!("Unable to format the following event. Name: {}; Fields: {:?}\n", + event.metadata().name(), event.fields()); + let mut writer = self.make_writer.make_writer_for(event.metadata()); + let res = io::Write::write_all(&mut writer, err_msg.as_bytes()); + if let Err(e) = res { + eprintln!("[tracing-subscriber] Unable to write an \"event formatting error\" to the Writer for this Subscriber! Error: {}\n", e); + } } buf.clear(); @@ -821,7 +1034,7 @@ where /// If this returns `None`, then no span exists for that ID (either it has /// closed or the ID is invalid). /// - /// [stored data]: ../registry/struct.SpanRef.html + /// [stored data]: crate::registry::SpanRef #[inline] pub fn span(&self, id: &Id) -> Option<SpanRef<'_, S>> where @@ -844,7 +1057,7 @@ where /// /// If this returns `None`, then we are not currently within a span. /// - /// [stored data]: ../registry/struct.SpanRef.html + /// [stored data]: crate::registry::SpanRef #[inline] pub fn lookup_current(&self) -> Option<SpanRef<'_, S>> where @@ -1030,6 +1243,60 @@ mod test { } #[test] + fn format_error_print_to_stderr() { + struct AlwaysError; + + impl std::fmt::Debug for AlwaysError { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + Err(std::fmt::Error) + } + } + + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime) + .finish(); + + with_default(subscriber, || { + tracing::info!(?AlwaysError); + }); + let actual = sanitize_timings(make_writer.get_string()); + + // Only assert the start because the line number and callsite may change. + let expected = concat!("Unable to format the following event. Name: event ", file!(), ":"); + assert!(actual.as_str().starts_with(expected), "\nactual = {}\nshould start with expected = {}\n", actual, expected); + } + + #[test] + fn format_error_ignore_if_log_internal_errors_is_false() { + struct AlwaysError; + + impl std::fmt::Debug for AlwaysError { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + Err(std::fmt::Error) + } + } + + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime) + .log_internal_errors(false) + .finish(); + + with_default(subscriber, || { + tracing::info!(?AlwaysError); + }); + let actual = sanitize_timings(make_writer.get_string()); + assert_eq!("", actual.as_str()); + } + + #[test] fn synthesize_span_none() { let make_writer = MockMakeWriter::default(); let subscriber = crate::fmt::Subscriber::builder() diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs b/vendor/tracing-subscriber/src/fmt/format/json.rs index cc86f03c7..c2f4d3755 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs +++ b/vendor/tracing-subscriber/src/fmt/format/json.rs @@ -23,25 +23,42 @@ use tracing_serde::AsSerde; #[cfg(feature = "tracing-log")] use tracing_log::NormalizeEvent; -/// Marker for `Format` that indicates that the verbose JSON log format should be used. +/// Marker for [`Format`] that indicates that the newline-delimited JSON log +/// format should be used. /// -/// The full format includes fields from all entered spans. +/// This formatter is intended for production use with systems where structured +/// logs are consumed as JSON by analysis and viewing tools. The JSON output is +/// not optimized for human readability; instead, it should be pretty-printed +/// using external JSON tools such as `jq`, or using a JSON log viewer. /// /// # Example Output /// -/// ```json -/// { -/// "timestamp":"Feb 20 11:28:15.096", -/// "level":"INFO", -/// "fields":{"message":"some message","key":"value"} -/// "target":"mycrate", -/// "span":{name":"leaf"}, -/// "spans":[{"name":"root"},{"name":"leaf"}], -/// } -/// ``` +/// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt-json +/// <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s +/// <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-json` +/// {"timestamp":"2022-02-15T18:47:10.821315Z","level":"INFO","fields":{"message":"preparing to shave yaks","number_of_yaks":3},"target":"fmt_json"} +/// {"timestamp":"2022-02-15T18:47:10.821422Z","level":"INFO","fields":{"message":"shaving yaks"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821495Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821546Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821598Z","level":"DEBUG","fields":{"yak":1,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821637Z","level":"TRACE","fields":{"yaks_shaved":1},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821684Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821727Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821773Z","level":"DEBUG","fields":{"yak":2,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821806Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821909Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821956Z","level":"WARN","fields":{"message":"could not locate yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.822006Z","level":"DEBUG","fields":{"yak":3,"shaved":false},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822041Z","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822079Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822117Z","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"} +/// </pre> /// /// # Options /// +/// This formatter exposes additional options to configure the structure of the +/// output JSON objects: +/// /// - [`Json::flatten_event`] can be used to enable flattening event fields into /// the root /// - [`Json::with_current_span`] can be used to control logging of the current @@ -52,9 +69,23 @@ use tracing_log::NormalizeEvent; /// By default, event fields are not flattened, and both current span and span /// list are logged. /// -/// [`Json::flatten_event`]: #method.flatten_event -/// [`Json::with_current_span`]: #method.with_current_span -/// [`Json::with_span_list`]: #method.with_span_list +/// # Valuable Support +/// +/// Experimental support is available for using the [`valuable`] crate to record +/// user-defined values as structured JSON. When the ["valuable" unstable +/// feature][unstable] is enabled, types implementing [`valuable::Valuable`] will +/// be recorded as structured JSON, rather than +/// using their [`std::fmt::Debug`] implementations. +/// +/// **Note**: This is an experimental feature. [Unstable features][unstable] +/// must be enabled in order to use `valuable` support. +/// +/// [`Json::flatten_event`]: Json::flatten_event() +/// [`Json::with_current_span`]: Json::with_current_span() +/// [`Json::with_span_list`]: Json::with_span_list() +/// [`valuable`]: https://crates.io/crates/valuable +/// [unstable]: crate#unstable-features +/// [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Json { pub(crate) flatten_event: bool, @@ -243,6 +274,18 @@ where serializer.serialize_entry("target", meta.target())?; } + if self.display_filename { + if let Some(filename) = meta.file() { + serializer.serialize_entry("filename", filename)?; + } + } + + if self.display_line_number { + if let Some(line_number) = meta.line() { + serializer.serialize_entry("line_number", &line_number)?; + } + } + if self.format.display_current_span { if let Some(ref span) = current_span { serializer @@ -298,7 +341,6 @@ impl Default for Json { /// The JSON [`FormatFields`] implementation. /// -/// [`FormatFields`]: trait.FormatFields.html #[derive(Debug)] pub struct JsonFields { // reserve the ability to add fields to this without causing a breaking @@ -309,7 +351,6 @@ pub struct JsonFields { impl JsonFields { /// Returns a new JSON [`FormatFields`] implementation. /// - /// [`FormatFields`]: trait.FormatFields.html pub fn new() -> Self { Self { _private: () } } @@ -378,9 +419,8 @@ impl<'a> FormatFields<'a> for JsonFields { /// The [visitor] produced by [`JsonFields`]'s [`MakeVisitor`] implementation. /// -/// [visitor]: ../../field/trait.Visit.html -/// [`JsonFields`]: struct.JsonFields.html -/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html +/// [visitor]: crate::field::Visit +/// [`MakeVisitor`]: crate::field::MakeVisitor pub struct JsonVisitor<'a> { values: BTreeMap<&'a str, serde_json::Value>, writer: &'a mut dyn Write, @@ -435,6 +475,26 @@ impl<'a> crate::field::VisitOutput<fmt::Result> for JsonVisitor<'a> { } impl<'a> field::Visit for JsonVisitor<'a> { + #[cfg(all(tracing_unstable, feature = "valuable"))] + fn record_value(&mut self, field: &Field, value: valuable_crate::Value<'_>) { + let value = match serde_json::to_value(valuable_serde::Serializable::new(value)) { + Ok(value) => value, + Err(_e) => { + #[cfg(debug_assertions)] + unreachable!( + "`valuable::Valuable` implementations should always serialize \ + successfully, but an error occurred: {}", + _e, + ); + + #[cfg(not(debug_assertions))] + return; + } + }; + + self.values.insert(field.name(), value); + } + /// Visit a double precision floating point value. fn record_f64(&mut self, field: &Field, value: f64) { self.values @@ -488,6 +548,7 @@ mod test { use tracing::{self, subscriber::with_default}; use std::fmt; + use std::path::Path; struct MockTime; impl FormatTime for MockTime { @@ -516,6 +577,50 @@ mod test { } #[test] + fn json_filename() { + let current_path = Path::new("tracing-subscriber") + .join("src") + .join("fmt") + .join("format") + .join("json.rs") + .to_str() + .expect("path must be valid unicode") + // escape windows backslashes + .replace('\\', "\\\\"); + let expected = + &format!("{}{}{}", + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"filename\":\"", + current_path, + "\",\"fields\":{\"message\":\"some json test\"}}\n"); + let subscriber = subscriber() + .flatten_event(false) + .with_current_span(true) + .with_file(true) + .with_span_list(true); + test_json(expected, subscriber, || { + let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let _guard = span.enter(); + tracing::info!("some json test"); + }); + } + + #[test] + fn json_line_number() { + let expected = + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"line_number\":42,\"fields\":{\"message\":\"some json test\"}}\n"; + let subscriber = subscriber() + .flatten_event(false) + .with_current_span(true) + .with_line_number(true) + .with_span_list(true); + test_json_with_line_number(expected, subscriber, || { + let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let _guard = span.enter(); + tracing::info!("some json test"); + }); + } + + #[test] fn json_flattened_event() { let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"message\":\"some json test\"}\n"; @@ -747,4 +852,34 @@ mod test { serde_json::from_str(actual).unwrap() ); } + + fn test_json_with_line_number<T>( + expected: &str, + builder: crate::fmt::SubscriberBuilder<JsonFields, Format<Json>>, + producer: impl FnOnce() -> T, + ) { + let make_writer = MockMakeWriter::default(); + let subscriber = builder + .with_writer(make_writer.clone()) + .with_timer(MockTime) + .finish(); + + with_default(subscriber, producer); + + let buf = make_writer.buf(); + let actual = std::str::from_utf8(&buf[..]).unwrap(); + let mut expected = + serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected) + .unwrap(); + let expect_line_number = expected.remove("line_number").is_some(); + let mut actual: std::collections::HashMap<&str, serde_json::Value> = + serde_json::from_str(actual).unwrap(); + let line_number = actual.remove("line_number"); + if expect_line_number { + assert_eq!(line_number.map(|x| x.is_number()), Some(true)); + } else { + assert!(line_number.is_none()); + } + assert_eq!(actual, expected); + } } diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/format/mod.rs b/vendor/tracing-subscriber/src/fmt/format/mod.rs index 9001e102e..b8a482e55 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/format/mod.rs +++ b/vendor/tracing-subscriber/src/fmt/format/mod.rs @@ -1,4 +1,33 @@ //! Formatters for logging `tracing` events. +//! +//! This module provides several formatter implementations, as well as utilities +//! for implementing custom formatters. +//! +//! # Formatters +//! This module provides a number of formatter implementations: +//! +//! * [`Full`]: The default formatter. This emits human-readable, +//! single-line logs for each event that occurs, with the current span context +//! displayed before the formatted representation of the event. See +//! [here](Full#example-output) for sample output. +//! +//! * [`Compact`]: A variant of the default formatter, optimized for +//! short line lengths. Fields from the current span context are appended to +//! the fields of the formatted event, and span names are not shown; the +//! verbosity level is abbreviated to a single character. See +//! [here](Compact#example-output) for sample output. +//! +//! * [`Pretty`]: Emits excessively pretty, multi-line logs, optimized +//! for human readability. This is primarily intended to be used in local +//! development and debugging, or for command-line applications, where +//! automated analysis and compact storage of logs is less of a priority than +//! readability and visual appeal. See [here](Pretty#example-output) +//! for sample output. +//! +//! * [`Json`]: Outputs newline-delimited JSON logs. This is intended +//! for production use with systems where structured logs are consumed as JSON +//! by analysis and viewing tools. The JSON output is not optimized for human +//! readability. See [here](Json#example-output) for sample output. use super::time::{FormatTime, SystemTime}; use crate::{ field::{MakeOutput, MakeVisitor, RecordFields, VisitFmt, VisitOutput}, @@ -17,7 +46,7 @@ use tracing_core::{ use tracing_log::NormalizeEvent; #[cfg(feature = "ansi")] -use ansi_term::{Colour, Style}; +use nu_ansi_term::{Color, Style}; #[cfg(feature = "json")] mod json; @@ -72,7 +101,7 @@ pub use pretty::*; /// does not support ANSI escape codes (such as a log file), and they should /// not be emitted. /// -/// Crates like [`ansi_term`] and [`owo-colors`] can be used to add ANSI +/// Crates like [`nu_ansi_term`] and [`owo-colors`] can be used to add ANSI /// escape codes to formatted output. /// /// * The actual [`Event`] to be formatted. @@ -153,13 +182,14 @@ pub use pretty::*; /// DEBUG yak_shaving::shaver: some-span{field-on-span=foo}: started shaving yak /// ``` /// +/// [`layer::Context`]: crate::layer::Context /// [`fmt::Layer`]: super::Layer /// [`fmt::Subscriber`]: super::Subscriber /// [`Event`]: tracing::Event /// [implements `FormatFields`]: super::FmtContext#impl-FormatFields<'writer> /// [ANSI terminal escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code /// [`Writer::has_ansi_escapes`]: Writer::has_ansi_escapes -/// [`ansi_term`]: https://crates.io/crates/ansi_term +/// [`nu_ansi_term`]: https://crates.io/crates/nu_ansi_term /// [`owo-colors`]: https://crates.io/crates/owo-colors /// [default formatter]: Full pub trait FormatEvent<S, N> @@ -197,8 +227,8 @@ where /// time a span or event with fields is recorded, the subscriber will format /// those fields with its associated `FormatFields` implementation. /// -/// [set of fields]: ../field/trait.RecordFields.html -/// [`FmtSubscriber`]: ../fmt/struct.Subscriber.html +/// [set of fields]: crate::field::RecordFields +/// [`FmtSubscriber`]: super::Subscriber pub trait FormatFields<'writer> { /// Format the provided `fields` to the provided [`Writer`], returning a result. fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result; @@ -251,7 +281,6 @@ pub fn json() -> Format<Json> { /// Returns a [`FormatFields`] implementation that formats fields using the /// provided function or closure. /// -/// [`FormatFields`]: trait.FormatFields.html pub fn debug_fn<F>(f: F) -> FieldFn<F> where F: Fn(&mut Writer<'_>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone, @@ -272,6 +301,8 @@ where /// /// Additionally, a `Writer` may expose additional `tracing`-specific /// information to the formatter implementation. +/// +/// [fields]: tracing_core::field pub struct Writer<'writer> { writer: &'writer mut dyn fmt::Write, // TODO(eliza): add ANSI support @@ -281,28 +312,76 @@ pub struct Writer<'writer> { /// A [`FormatFields`] implementation that formats fields by calling a function /// or closure. /// -/// [`FormatFields`]: trait.FormatFields.html #[derive(Debug, Clone)] pub struct FieldFn<F>(F); /// The [visitor] produced by [`FieldFn`]'s [`MakeVisitor`] implementation. /// -/// [visitor]: ../../field/trait.Visit.html -/// [`FieldFn`]: struct.FieldFn.html -/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html +/// [visitor]: super::super::field::Visit +/// [`MakeVisitor`]: super::super::field::MakeVisitor pub struct FieldFnVisitor<'a, F> { f: F, writer: Writer<'a>, result: fmt::Result, } -/// Marker for `Format` that indicates that the compact log format should be used. +/// Marker for [`Format`] that indicates that the compact log format should be used. +/// +/// The compact format includes fields from all currently entered spans, after +/// the event's fields. Span names are listed in order before fields are +/// displayed. +/// +/// # Example Output /// -/// The compact format only includes the fields from the most recently entered span. +/// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt-compact +/// <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s +/// <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-compact` +/// <font color="#AAAAAA">2022-02-17T19:51:05.809287Z </font><font color="#4E9A06"> INFO</font> <b>fmt_compact</b><font color="#AAAAAA">: preparing to shave yaks </font><i>number_of_yaks</i><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809367Z </font><font color="#4E9A06"> INFO</font> <b>shaving_yaks</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: shaving yaks </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809414Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!" </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=1</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809443Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: yak shaved successfully </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=1</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809477Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks</b>: <b>yak_events</b><font color="#AAAAAA">: </font><i>yak</i><font color="#AAAAAA">=1 </font><i>shaved</i><font color="#AAAAAA">=true </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809500Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: </font><i>yaks_shaved</i><font color="#AAAAAA">=1 </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809531Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!" </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=2</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809554Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: yak shaved successfully </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=2</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809581Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks</b>: <b>yak_events</b><font color="#AAAAAA">: </font><i>yak</i><font color="#AAAAAA">=2 </font><i>shaved</i><font color="#AAAAAA">=true </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809606Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: </font><i>yaks_shaved</i><font color="#AAAAAA">=2 </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809635Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!" </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809664Z </font><font color="#C4A000"> WARN</font> <b>shaving_yaks</b>:<b>shave</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: could not locate yak </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3 </font><font color="#AAAAAA"><i>yak</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809693Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks</b>: <b>yak_events</b><font color="#AAAAAA">: </font><i>yak</i><font color="#AAAAAA">=3 </font><i>shaved</i><font color="#AAAAAA">=false </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809717Z </font><font color="#CC0000">ERROR</font> <b>shaving_yaks</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: failed to shave yak </font><i>yak</i><font color="#AAAAAA">=3 </font><i>error</i><font color="#AAAAAA">=missing yak </font><i>error.sources</i><font color="#AAAAAA">=[out of space, out of cash] </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809743Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks</b>: <b>fmt_compact::yak_shave</b><font color="#AAAAAA">: </font><i>yaks_shaved</i><font color="#AAAAAA">=2 </font><font color="#AAAAAA"><i>yaks</i></font><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-17T19:51:05.809768Z </font><font color="#4E9A06"> INFO</font> <b>fmt_compact</b><font color="#AAAAAA">: yak shaving completed </font><i>all_yaks_shaved</i><font color="#AAAAAA">=false</font> +/// +/// </pre> #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] pub struct Compact; -/// Marker for `Format` that indicates that the verbose log format should be used. +/// Marker for [`Format`] that indicates that the default log format should be used. +/// +/// This formatter shows the span context before printing event data. Spans are +/// displayed including their names and fields. /// -/// The full format includes fields from all entered spans. +/// # Example Output +/// +/// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt +/// <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s +/// <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt` +/// <font color="#AAAAAA">2022-02-15T18:40:14.289898Z </font><font color="#4E9A06"> INFO</font> fmt: preparing to shave yaks <i>number_of_yaks</i><font color="#AAAAAA">=3</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.289974Z </font><font color="#4E9A06"> INFO</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: shaving yaks</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290011Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=1</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!"</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290038Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=1</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: yak shaved successfully</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290070Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: yak_events: </font><i>yak</i><font color="#AAAAAA">=1 </font><i>shaved</i><font color="#AAAAAA">=true</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290089Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: </font><i>yaks_shaved</i><font color="#AAAAAA">=1</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290114Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=2</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!"</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290134Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=2</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: yak shaved successfully</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290157Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: yak_events: </font><i>yak</i><font color="#AAAAAA">=2 </font><i>shaved</i><font color="#AAAAAA">=true</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290174Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: </font><i>yaks_shaved</i><font color="#AAAAAA">=2</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290198Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: hello! I'm gonna shave a yak </font><i>excitement</i><font color="#AAAAAA">="yay!"</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290222Z </font><font color="#C4A000"> WARN</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">:</font><b>shave{</b><i>yak</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: could not locate yak</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290247Z </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: yak_events: </font><i>yak</i><font color="#AAAAAA">=3 </font><i>shaved</i><font color="#AAAAAA">=false</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290268Z </font><font color="#CC0000">ERROR</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: failed to shave yak </font><i>yak</i><font color="#AAAAAA">=3 </font><i>error</i><font color="#AAAAAA">=missing yak </font><i>error.sources</i><font color="#AAAAAA">=[out of space, out of cash]</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290287Z </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b><i>yaks</i><font color="#AAAAAA">=3</font><b>}</b><font color="#AAAAAA">: fmt::yak_shave: </font><i>yaks_shaved</i><font color="#AAAAAA">=2</font> +/// <font color="#AAAAAA">2022-02-15T18:40:14.290309Z </font><font color="#4E9A06"> INFO</font> fmt: yak shaving completed. <i>all_yaks_shaved</i><font color="#AAAAAA">=false</font> +/// </pre> #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] pub struct Full; @@ -311,8 +390,11 @@ pub struct Full; /// You will usually want to use this as the `FormatEvent` for a `FmtSubscriber`. /// /// The default logging format, [`Full`] includes all fields in each event and its containing -/// spans. The [`Compact`] logging format includes only the fields from the most-recently-entered -/// span. +/// spans. The [`Compact`] logging format is intended to produce shorter log +/// lines; it displays each event's fields, along with fields from the current +/// span context, but other information is abbreviated. The [`Pretty`] logging +/// format is an extra-verbose, multi-line human-readable logging format +/// intended for use in development. #[derive(Debug, Clone)] pub struct Format<F = Full, T = SystemTime> { format: F, @@ -323,6 +405,8 @@ pub struct Format<F = Full, T = SystemTime> { pub(crate) display_level: bool, pub(crate) display_thread_id: bool, pub(crate) display_thread_name: bool, + pub(crate) display_filename: bool, + pub(crate) display_line_number: bool, } // === impl Writer === @@ -499,6 +583,8 @@ impl Default for Format<Full, SystemTime> { display_level: true, display_thread_id: false, display_thread_name: false, + display_filename: false, + display_line_number: false, } } } @@ -517,6 +603,8 @@ impl<F, T> Format<F, T> { display_level: self.display_level, display_thread_id: self.display_thread_id, display_thread_name: self.display_thread_name, + display_filename: self.display_filename, + display_line_number: self.display_line_number, } } @@ -554,6 +642,8 @@ impl<F, T> Format<F, T> { display_level: self.display_level, display_thread_id: self.display_thread_id, display_thread_name: self.display_thread_name, + display_filename: true, + display_line_number: true, } } @@ -571,8 +661,6 @@ impl<F, T> Format<F, T> { /// /// - [`Format::flatten_event`] can be used to enable flattening event fields into the root /// object. - /// - /// [`Format::flatten_event`]: #method.flatten_event #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn json(self) -> Format<Json, T> { @@ -585,6 +673,8 @@ impl<F, T> Format<F, T> { display_level: self.display_level, display_thread_id: self.display_thread_id, display_thread_name: self.display_thread_name, + display_filename: self.display_filename, + display_line_number: self.display_line_number, } } @@ -612,6 +702,8 @@ impl<F, T> Format<F, T> { display_level: self.display_level, display_thread_id: self.display_thread_id, display_thread_name: self.display_thread_name, + display_filename: self.display_filename, + display_line_number: self.display_line_number, } } @@ -626,6 +718,8 @@ impl<F, T> Format<F, T> { display_level: self.display_level, display_thread_id: self.display_thread_id, display_thread_name: self.display_thread_name, + display_filename: self.display_filename, + display_line_number: self.display_line_number, } } @@ -654,9 +748,9 @@ impl<F, T> Format<F, T> { } /// Sets whether or not the [thread ID] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html + /// [thread ID]: std::thread::ThreadId pub fn with_thread_ids(self, display_thread_id: bool) -> Format<F, T> { Format { display_thread_id, @@ -665,9 +759,9 @@ impl<F, T> Format<F, T> { } /// Sets whether or not the [name] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads + /// [name]: std::thread#naming-threads pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> { Format { display_thread_name, @@ -675,6 +769,38 @@ impl<F, T> Format<F, T> { } } + /// Sets whether or not an event's [source code file path][file] is + /// displayed. + /// + /// [file]: tracing_core::Metadata::file + pub fn with_file(self, display_filename: bool) -> Format<F, T> { + Format { + display_filename, + ..self + } + } + + /// Sets whether or not an event's [source code line number][line] is + /// displayed. + /// + /// [line]: tracing_core::Metadata::line + pub fn with_line_number(self, display_line_number: bool) -> Format<F, T> { + Format { + display_line_number, + ..self + } + } + + /// Sets whether or not the source code location from which an event + /// originated is displayed. + /// + /// This is equivalent to calling [`Format::with_file`] and + /// [`Format::with_line_number`] with the same value. + pub fn with_source_location(self, display_location: bool) -> Self { + self.with_line_number(display_location) + .with_file(display_location) + } + #[inline] fn format_timestamp(&self, writer: &mut Writer<'_>) -> fmt::Result where @@ -692,14 +818,24 @@ impl<F, T> Format<F, T> { if writer.has_ansi_escapes() { let style = Style::new().dimmed(); write!(writer, "{}", style.prefix())?; - self.timer.format_time(writer)?; + + // If getting the timestamp failed, don't bail --- only bail on + // formatting errors. + if self.timer.format_time(writer).is_err() { + writer.write_str("<unknown time>")?; + } + write!(writer, "{} ", style.suffix())?; return Ok(()); } } // Otherwise, just format the timestamp without ANSI formatting. - self.timer.format_time(writer)?; + // If getting the timestamp failed, don't bail --- only bail on + // formatting errors. + if self.timer.format_time(writer).is_err() { + writer.write_str("<unknown time>")?; + } writer.write_char(' ') } } @@ -714,7 +850,7 @@ impl<T> Format<Json, T> { /// ```ignore,json /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate", "message":"some message", "key": "value"} /// ``` - /// See [`Json`](../format/struct.Json.html). + /// See [`Json`][super::format::Json]. #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn flatten_event(mut self, flatten_event: bool) -> Format<Json, T> { @@ -725,7 +861,7 @@ impl<T> Format<Json, T> { /// Sets whether or not the formatter will include the current span in /// formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][Json] #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn with_current_span(mut self, display_current_span: bool) -> Format<Json, T> { @@ -736,7 +872,7 @@ impl<T> Format<Json, T> { /// Sets whether or not the formatter will include a list (from root to /// leaf) of all currently entered spans in formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][Json] #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn with_span_list(mut self, display_span_list: bool) -> Format<Json, T> { @@ -840,6 +976,34 @@ where )?; } + let line_number = if self.display_line_number { + meta.line() + } else { + None + }; + + if self.display_filename { + if let Some(filename) = meta.file() { + write!( + writer, + "{}{}{}", + dimmed.paint(filename), + dimmed.paint(":"), + if line_number.is_some() { "" } else { " " } + )?; + } + } + + if let Some(line_number) = line_number { + write!( + writer, + "{}{}:{} ", + dimmed.prefix(), + line_number, + dimmed.suffix() + )?; + } + ctx.format_fields(writer.by_ref(), event)?; writeln!(writer) } @@ -918,23 +1082,49 @@ where }; write!(writer, "{}", fmt_ctx)?; + let bold = writer.bold(); + let dimmed = writer.dimmed(); + + let mut needs_space = false; if self.display_target { - write!( - writer, - "{}{} ", - writer.bold().paint(meta.target()), - writer.dimmed().paint(":") - )?; + write!(writer, "{}{}", bold.paint(meta.target()), dimmed.paint(":"))?; + needs_space = true; + } + + if self.display_filename { + if let Some(filename) = meta.file() { + if self.display_target { + writer.write_char(' ')?; + } + write!(writer, "{}{}", bold.paint(filename), dimmed.paint(":"))?; + needs_space = true; + } + } + + if self.display_line_number { + if let Some(line_number) = meta.line() { + write!( + writer, + "{}{}{}{}", + bold.prefix(), + line_number, + bold.suffix(), + dimmed.paint(":") + )?; + needs_space = true; + } + } + + if needs_space { + writer.write_char(' ')?; } ctx.format_fields(writer.by_ref(), event)?; - let dimmed = writer.dimmed(); for span in ctx .event_scope() .into_iter() - .map(crate::registry::Scope::from_root) - .flatten() + .flat_map(crate::registry::Scope::from_root) { let exts = span.extensions(); if let Some(fields) = exts.get::<FormattedFields<N>>() { @@ -962,7 +1152,6 @@ where /// The default [`FormatFields`] implementation. /// -/// [`FormatFields`]: trait.FormatFields.html #[derive(Debug)] pub struct DefaultFields { // reserve the ability to add fields to this without causing a breaking @@ -984,7 +1173,6 @@ pub struct DefaultVisitor<'a> { impl DefaultFields { /// Returns a new default [`FormatFields`] implementation. /// - /// [`FormatFields`]: trait.FormatFields.html pub fn new() -> Self { Self { _private: () } } @@ -1201,6 +1389,14 @@ impl Style { fn paint(&self, d: impl fmt::Display) -> impl fmt::Display { d } + + fn prefix(&self) -> impl fmt::Display { + "" + } + + fn suffix(&self) -> impl fmt::Display { + "" + } } struct FmtThreadName<'a> { @@ -1288,11 +1484,11 @@ impl<'a> fmt::Display for FmtLevel<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.ansi { match *self.level { - Level::TRACE => write!(f, "{}", Colour::Purple.paint(TRACE_STR)), - Level::DEBUG => write!(f, "{}", Colour::Blue.paint(DEBUG_STR)), - Level::INFO => write!(f, "{}", Colour::Green.paint(INFO_STR)), - Level::WARN => write!(f, "{}", Colour::Yellow.paint(WARN_STR)), - Level::ERROR => write!(f, "{}", Colour::Red.paint(ERROR_STR)), + Level::TRACE => write!(f, "{}", Color::Purple.paint(TRACE_STR)), + Level::DEBUG => write!(f, "{}", Color::Blue.paint(DEBUG_STR)), + Level::INFO => write!(f, "{}", Color::Green.paint(INFO_STR)), + Level::WARN => write!(f, "{}", Color::Yellow.paint(WARN_STR)), + Level::ERROR => write!(f, "{}", Color::Red.paint(ERROR_STR)), } } else { match *self.level { @@ -1366,7 +1562,7 @@ impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> { /// Configures what points in the span lifecycle are logged as events. /// -/// See also [`with_span_events`](../struct.SubscriberBuilder.html#method.with_span_events). +/// See also [`with_span_events`](super::SubscriberBuilder.html::with_span_events). #[derive(Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct FmtSpan(u8); @@ -1528,7 +1724,9 @@ pub(super) mod test { }; use super::*; - use std::fmt; + + use regex::Regex; + use std::{fmt, path::Path}; pub(crate) struct MockTime; impl FormatTime for MockTime { @@ -1550,7 +1748,7 @@ pub(super) mod test { .with_thread_names(false); #[cfg(feature = "ansi")] let subscriber = subscriber.with_ansi(false); - run_test(subscriber, make_writer, "hello\n") + assert_info_hello(subscriber, make_writer, "hello\n") } fn test_ansi<T>( @@ -1598,6 +1796,124 @@ pub(super) mod test { run_test(subscriber, make_writer, expected); } + #[test] + fn with_line_number_and_file_name() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_file(true) + .with_line_number(true) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime); + + let expected = Regex::new(&format!( + "^fake time tracing_subscriber::fmt::format::test: {}:[0-9]+: hello\n$", + current_path() + // if we're on Windows, the path might contain backslashes, which + // have to be escpaed before compiling the regex. + .replace('\\', "\\\\") + )) + .unwrap(); + let _default = set_default(&subscriber.into()); + tracing::info!("hello"); + let res = make_writer.get_string(); + assert!(expected.is_match(&res)); + } + + #[test] + fn with_line_number() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_line_number(true) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime); + + let expected = + Regex::new("^fake time tracing_subscriber::fmt::format::test: [0-9]+: hello\n$") + .unwrap(); + let _default = set_default(&subscriber.into()); + tracing::info!("hello"); + let res = make_writer.get_string(); + assert!(expected.is_match(&res)); + } + + #[test] + fn with_filename() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_file(true) + .with_level(false) + .with_ansi(false) + .with_timer(MockTime); + let expected = &format!( + "fake time tracing_subscriber::fmt::format::test: {}: hello\n", + current_path(), + ); + assert_info_hello(subscriber, make_writer, expected); + } + + #[test] + fn with_thread_ids() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_thread_ids(true) + .with_ansi(false) + .with_timer(MockTime); + let expected = + "fake time INFO ThreadId(NUMERIC) tracing_subscriber::fmt::format::test: hello\n"; + + assert_info_hello_ignore_numeric(subscriber, make_writer, expected); + } + + #[test] + fn pretty_default() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .pretty() + .with_writer(make_writer.clone()) + .with_ansi(false) + .with_timer(MockTime); + let expected = format!( + r#" fake time INFO tracing_subscriber::fmt::format::test: hello + at {}:NUMERIC + +"#, + file!() + ); + + assert_info_hello_ignore_numeric(subscriber, make_writer, &expected) + } + + fn assert_info_hello(subscriber: impl Into<Dispatch>, buf: MockMakeWriter, expected: &str) { + let _default = set_default(&subscriber.into()); + tracing::info!("hello"); + let result = buf.get_string(); + + assert_eq!(expected, result) + } + + // When numeric characters are used they often form a non-deterministic value as they usually represent things like a thread id or line number. + // This assert method should be used when non-deterministic numeric characters are present. + fn assert_info_hello_ignore_numeric( + subscriber: impl Into<Dispatch>, + buf: MockMakeWriter, + expected: &str, + ) { + let _default = set_default(&subscriber.into()); + tracing::info!("hello"); + + let regex = Regex::new("[0-9]+").unwrap(); + let result = buf.get_string(); + let result_cleaned = regex.replace_all(&result, "NUMERIC"); + + assert_eq!(expected, result_cleaned) + } + fn test_overridden_parents<T>( expected: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, @@ -1606,14 +1922,14 @@ pub(super) mod test { T: Send + Sync + 'static, { let make_writer = MockMakeWriter::default(); - let collector = builder + let subscriber = builder .with_writer(make_writer.clone()) .with_level(false) .with_ansi(false) .with_timer(MockTime) .finish(); - with_default(collector, || { + with_default(subscriber, || { let span1 = tracing::info_span!("span1", span = 1); let span2 = tracing::info_span!(parent: &span1, "span2", span = 2); tracing::info!(parent: &span2, "hello"); @@ -1659,6 +1975,21 @@ pub(super) mod test { mod default { use super::*; + + #[test] + fn with_thread_ids() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .with_writer(make_writer.clone()) + .with_thread_ids(true) + .with_ansi(false) + .with_timer(MockTime); + let expected = + "fake time INFO ThreadId(NUMERIC) tracing_subscriber::fmt::format::test: hello\n"; + + assert_info_hello_ignore_numeric(subscriber, make_writer, expected); + } + #[cfg(feature = "ansi")] #[test] fn with_ansi_true() { @@ -1748,6 +2079,26 @@ pub(super) mod test { } } + mod pretty { + use super::*; + + #[test] + fn pretty_default() { + let make_writer = MockMakeWriter::default(); + let subscriber = crate::fmt::Subscriber::builder() + .pretty() + .with_writer(make_writer.clone()) + .with_ansi(false) + .with_timer(MockTime); + let expected = format!( + " fake time INFO tracing_subscriber::fmt::format::test: hello\n at {}:NUMERIC\n\n", + file!() + ); + + assert_info_hello_ignore_numeric(subscriber, make_writer, &expected) + } + } + #[test] fn format_nanos() { fn fmt(t: u64) -> String { @@ -1795,4 +2146,16 @@ pub(super) mod test { assert!(!f.contains(FmtSpan::EXIT)); assert!(f.contains(FmtSpan::CLOSE)); } + + /// Returns the test's module path. + fn current_path() -> String { + Path::new("tracing-subscriber") + .join("src") + .join("fmt") + .join("format") + .join("mod.rs") + .to_str() + .expect("path must not contain invalid unicode") + .to_owned() + } } diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/mod.rs b/vendor/tracing-subscriber/src/fmt/mod.rs index d5deb8f0c..025e17504 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/mod.rs +++ b/vendor/tracing-subscriber/src/fmt/mod.rs @@ -13,10 +13,12 @@ //! //! ```toml //! [dependencies] -//! tracing-subscriber = "0.2" +//! tracing-subscriber = "0.3" //! ``` //! -//! *Compiler support: requires rustc 1.39+* +//! *Compiler support: [requires `rustc` 1.49+][msrv]* +//! +//! [msrv]: super#supported-rust-versions //! //! Add the following to your executable to initialize the default subscriber: //! ```rust @@ -68,132 +70,25 @@ //! //! * [`format::Full`]: The default formatter. This emits human-readable, //! single-line logs for each event that occurs, with the current span context -//! displayed before the formatted representation of the event. +//! displayed before the formatted representation of the event. See +//! [here](format::Full#example-output) for sample output. //! -//! For example: -//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.59s -//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt` -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#4E9A06"> INFO</font> fmt: preparing to shave yaks number_of_yaks=3 -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#4E9A06"> INFO</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: shaving yaks -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=1<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!" -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=1<b>}</b>: fmt::yak_shave: yak shaved successfully -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=1 shaved=true -//! <font color="#AAAAAA">Oct 24 12:55:47.814 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=1 -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=2<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!" -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=2<b>}</b>: fmt::yak_shave: yak shaved successfully -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=2 shaved=true -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=2 -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=3<b>}</b>: fmt::yak_shave: hello! I'm gonna shave a yak excitement="yay!" -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#C4A000"> WARN</font> <b>shaving_yaks{</b>yaks=3<b>}</b>:<b>shave{</b>yak=3<b>}</b>: fmt::yak_shave: could not locate yak -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#3465A4">DEBUG</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: yak_events: yak=3 shaved=false -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#CC0000">ERROR</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: failed to shave yak yak=3 error=missing yak -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#75507B">TRACE</font> <b>shaving_yaks{</b>yaks=3<b>}</b>: fmt::yak_shave: yaks_shaved=2 -//! <font color="#AAAAAA">Oct 24 12:55:47.815 </font><font color="#4E9A06"> INFO</font> fmt: yak shaving completed all_yaks_shaved=false -//! </pre> +//! * [`format::Compact`]: A variant of the default formatter, optimized for +//! short line lengths. Fields from the current span context are appended to +//! the fields of the formatted event. See +//! [here](format::Compact#example-output) for sample output. //! //! * [`format::Pretty`]: Emits excessively pretty, multi-line logs, optimized //! for human readability. This is primarily intended to be used in local //! development and debugging, or for command-line applications, where //! automated analysis and compact storage of logs is less of a priority than -//! readability and visual appeal. -//! -//! For example: -//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.61s -//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-pretty` -//! Oct 24 12:57:29.386 <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: preparing to shave yaks, </font><font color="#4E9A06"><b>number_of_yaks</b></font><font color="#4E9A06">: 3</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:16<font color="#AAAAAA"><i> on</i></font> main -//! -//! Oct 24 12:57:29.386 <font color="#4E9A06"><b>fmt_pretty::yak_shave</b></font><font color="#4E9A06">: shaving yaks</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:38<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:22<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 1, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 1</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:22<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 2, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I'm gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: "yay!"</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:14<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#C4A000"><b>fmt_pretty::yak_shave</b></font><font color="#C4A000">: could not locate yak</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:16<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3 -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 3, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: false</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:43<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#CC0000"><b>fmt_pretty::yak_shave</b></font><font color="#CC0000">: failed to shave yak, </font><font color="#CC0000"><b>yak</b></font><font color="#CC0000">: 3, </font><font color="#CC0000"><b>error</b></font><font color="#CC0000">: missing yak</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:48<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:52<font color="#AAAAAA"><i> on</i></font> main -//! <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3 -//! -//! Oct 24 12:57:29.387 <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: yak shaving completed, </font><font color="#4E9A06"><b>all_yaks_shaved</b></font><font color="#4E9A06">: false</font> -//! <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:19<font color="#AAAAAA"><i> on</i></font> main -//! </pre> +//! readability and visual appeal. See [here](format::Pretty#example-output) +//! for sample output. //! //! * [`format::Json`]: Outputs newline-delimited JSON logs. This is intended //! for production use with systems where structured logs are consumed as JSON -//! by analysis and viewing tools. The JSON output, as seen below, is *not* -//! optimized for human readability. -//! -//! For example: -//! <pre><font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 1.58s -//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-json` -//! {"timestamp":"Oct 24 13:00:00.873","level":"INFO","fields":{"message":"preparing to shave yaks","number_of_yaks":3},"target":"fmt_json"} -//! {"timestamp":"Oct 24 13:00:00.874","level":"INFO","fields":{"message":"shaving yaks"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"1","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"1","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"DEBUG","fields":{"yak":1,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"yaks_shaved":1},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"2","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"2","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"DEBUG","fields":{"yak":2,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.874","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"3","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.875","level":"WARN","fields":{"message":"could not locate yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":"3","name":"shave"}]} -//! {"timestamp":"Oct 24 13:00:00.875","level":"DEBUG","fields":{"yak":3,"shaved":false},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.875","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.875","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} -//! {"timestamp":"Oct 24 13:00:00.875","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"} -//! </pre> +//! by analysis and viewing tools. The JSON output is not optimized for human +//! readability. See [here](format::Json#example-output) for sample output. //! //! ### Customizing Formatters //! @@ -221,7 +116,7 @@ //! .with_thread_names(true) // include the name of the current thread //! .compact(); // use the `Compact` formatting style. //! -//! // Create a `fmt` collector that uses our custom event format, and set it +//! // Create a `fmt` subscriber that uses our custom event format, and set it //! // as the default. //! tracing_subscriber::fmt() //! .event_format(format) @@ -268,7 +163,7 @@ //! //! ### Composing Layers //! -//! Composing an [`EnvFilter`] `Layer` and a [format `Layer`](../fmt/struct.Layer.html): +//! Composing an [`EnvFilter`] `Layer` and a [format `Layer`][super::fmt::Layer]: //! //! ```rust //! use tracing_subscriber::{fmt, EnvFilter}; @@ -286,11 +181,10 @@ //! .init(); //! ``` //! -//! [`EnvFilter`]: ../filter/struct.EnvFilter.html +//! [`EnvFilter`]: super::filter::EnvFilter //! [`env_logger`]: https://docs.rs/env_logger/ -//! [`filter`]: ../filter/index.html -//! [`SubscriberBuilder`]: ./struct.SubscriberBuilder.html -//! [`FmtSubscriber`]: ./struct.Subscriber.html +//! [`filter`]: super::filter +//! [`FmtSubscriber`]: Subscriber //! [`Subscriber`]: //! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html //! [`tracing`]: https://crates.io/crates/tracing @@ -309,6 +203,7 @@ pub mod writer; pub use fmt_layer::{FmtContext, FormattedFields, Layer}; use crate::layer::Layer as _; +use crate::util::SubscriberInitExt; use crate::{ filter::LevelFilter, layer, @@ -348,6 +243,7 @@ pub type Formatter< /// Configures and constructs `Subscriber`s. #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] #[derive(Debug)] +#[must_use] pub struct SubscriberBuilder< N = format::DefaultFields, E = format::Format<format::Full>, @@ -417,7 +313,7 @@ pub struct SubscriberBuilder< /// ``` /// /// [formatting subscriber]: Subscriber -/// [`SubscriberBuilder::default()`]: SubscriberBuilder::default() +/// [`SubscriberBuilder::default()`]: SubscriberBuilder::default /// [`init`]: SubscriberBuilder::init() /// [`try_init`]: SubscriberBuilder::try_init() /// [`finish`]: SubscriberBuilder::finish() @@ -429,10 +325,11 @@ pub fn fmt() -> SubscriberBuilder { /// Returns a new [formatting layer] that can be [composed] with other layers to /// construct a [`Subscriber`]. /// -/// This is a shorthand for the equivalent [`Layer::default`] function. +/// This is a shorthand for the equivalent [`Layer::default()`] function. /// /// [formatting layer]: Layer /// [composed]: crate::layer +/// [`Layer::default()`]: Layer::default #[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub fn layer<S>() -> Layer<S> { Layer::default() @@ -444,8 +341,8 @@ impl Subscriber { /// /// This can be overridden with the [`SubscriberBuilder::with_max_level`] method. /// - /// [verbosity level]: https://docs.rs/tracing-core/0.1.5/tracing_core/struct.Level.html - /// [`SubscriberBuilder::with_max_level`]: struct.SubscriberBuilder.html#method.with_max_level + /// [verbosity level]: tracing_core::Level + /// [`SubscriberBuilder::with_max_level`]: SubscriberBuilder::with_max_level pub const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::INFO; /// Returns a new `SubscriberBuilder` for configuring a format subscriber. @@ -502,6 +399,11 @@ where } #[inline] + fn event_enabled(&self, event: &Event<'_>) -> bool { + self.inner.event_enabled(event) + } + + #[inline] fn event(&self, event: &Event<'_>) { self.inner.event(event); } @@ -565,6 +467,7 @@ impl Default for SubscriberBuilder { filter: Subscriber::DEFAULT_MAX_LEVEL, inner: Default::default(), } + .log_internal_errors(true) } } @@ -701,7 +604,7 @@ where /// `Layer`s added to this subscriber. /// /// [lifecycle]: https://docs.rs/tracing/latest/tracing/span/index.html#the-span-lifecycle - /// [time]: #method.without_time + /// [time]: SubscriberBuilder::without_time() pub fn with_span_events(self, kind: format::FmtSpan) -> Self { SubscriberBuilder { inner: self.inner.with_span_events(kind), @@ -719,6 +622,27 @@ where } } + /// Sets whether to write errors from [`FormatEvent`] to the writer. + /// Defaults to true. + /// + /// By default, `fmt::Layer` will write any `FormatEvent`-internal errors to + /// the writer. These errors are unlikely and will only occur if there is a + /// bug in the `FormatEvent` implementation or its dependencies. + /// + /// If writing to the writer fails, the error message is printed to stderr + /// as a fallback. + /// + /// [`FormatEvent`]: crate::fmt::FormatEvent + pub fn log_internal_errors( + self, + log_internal_errors: bool, + ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { + SubscriberBuilder { + inner: self.inner.log_internal_errors(log_internal_errors), + ..self + } + } + /// Sets whether or not an event's target is displayed. pub fn with_target( self, @@ -730,6 +654,34 @@ where } } + /// Sets whether or not an event's [source code file path][file] is + /// displayed. + /// + /// [file]: tracing_core::Metadata::file + pub fn with_file( + self, + display_filename: bool, + ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { + SubscriberBuilder { + inner: self.inner.with_file(display_filename), + ..self + } + } + + /// Sets whether or not an event's [source code line number][line] is + /// displayed. + /// + /// [line]: tracing_core::Metadata::line + pub fn with_line_number( + self, + display_line_number: bool, + ) -> SubscriberBuilder<N, format::Format<L, T>, F, W> { + SubscriberBuilder { + inner: self.inner.with_line_number(display_line_number), + ..self + } + } + /// Sets whether or not an event's level is displayed. pub fn with_level( self, @@ -742,9 +694,9 @@ where } /// Sets whether or not the [name] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads + /// [name]: std::thread#naming-threads pub fn with_thread_names( self, display_thread_names: bool, @@ -756,9 +708,9 @@ where } /// Sets whether or not the [thread ID] of the current thread is displayed - /// when formatting events + /// when formatting events. /// - /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html + /// [thread ID]: std::thread::ThreadId pub fn with_thread_ids( self, display_thread_ids: bool, @@ -796,7 +748,7 @@ where /// Sets the subscriber being built to use a JSON formatter. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::fmt::format::Json] #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn json( @@ -817,7 +769,7 @@ where impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json, T>, F, W> { /// Sets the json subscriber being built to flatten event metadata. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::fmt::format::Json] pub fn flatten_event( self, flatten_event: bool, @@ -831,7 +783,7 @@ impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json, /// Sets whether or not the JSON subscriber being built will include the current span /// in formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::fmt::format::Json] pub fn with_current_span( self, display_current_span: bool, @@ -845,7 +797,7 @@ impl<T, F, W> SubscriberBuilder<format::JsonFields, format::Format<format::Json, /// Sets whether or not the JSON subscriber being built will include a list (from /// root to leaf) of all currently entered spans in formatted events. /// - /// See [`format::Json`](../fmt/format/struct.Json.html) + /// See [`format::Json`][super::fmt::format::Json] pub fn with_span_list( self, display_span_list: bool, @@ -891,7 +843,7 @@ where } impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { - /// Sets the Visitor that the subscriber being built will use to record + /// Sets the field formatter that the subscriber being built will use to record /// fields. /// /// For example: @@ -967,8 +919,8 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// .try_init()?; /// # Ok(())} /// ``` - /// [`EnvFilter`]: ../filter/struct.EnvFilter.html - /// [`with_max_level`]: #method.with_max_level + /// [`EnvFilter`]: super::filter::EnvFilter + /// [`with_max_level`]: SubscriberBuilder::with_max_level() #[cfg(feature = "env-filter")] #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] pub fn with_env_filter( @@ -989,7 +941,7 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// subscriber. /// /// If the max level has already been set, or a [`EnvFilter`] was added by - /// [`with_filter`], this replaces that configuration with the new + /// [`with_env_filter`], this replaces that configuration with the new /// maximum level. /// /// # Examples @@ -1011,9 +963,9 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// .with_max_level(LevelFilter::OFF) /// .finish(); /// ``` - /// [verbosity level]: https://docs.rs/tracing-core/0.1.5/tracing_core/struct.Level.html - /// [`EnvFilter`]: ../filter/struct.EnvFilter.html - /// [`with_filter`]: #method.with_filter + /// [verbosity level]: tracing_core::Level + /// [`EnvFilter`]: struct@crate::filter::EnvFilter + /// [`with_env_filter`]: fn@Self::with_env_filter pub fn with_max_level( self, filter: impl Into<LevelFilter>, @@ -1025,8 +977,26 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { } } - /// Sets the function that the subscriber being built should use to format - /// events that occur. + /// Sets the [event formatter][`FormatEvent`] that the subscriber being built + /// will use to format events that occur. + /// + /// The event formatter may be any type implementing the [`FormatEvent`] + /// trait, which is implemented for all functions taking a [`FmtContext`], a + /// [`Writer`], and an [`Event`]. + /// + /// # Examples + /// + /// Setting a type implementing [`FormatEvent`] as the formatter: + /// + /// ```rust + /// use tracing_subscriber::fmt::format; + /// + /// let subscriber = tracing_subscriber::fmt() + /// .event_format(format().compact()) + /// .finish(); + /// ``` + /// + /// [`Writer`]: struct@self::format::Writer pub fn event_format<E2>(self, fmt_event: E2) -> SubscriberBuilder<N, E2, F, W> where E2: FormatEvent<Registry, N> + 'static, @@ -1053,8 +1023,6 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// .with_writer(io::stderr) /// .init(); /// ``` - /// - /// [`MakeWriter`]: trait.MakeWriter.html pub fn with_writer<W2>(self, make_writer: W2) -> SubscriberBuilder<N, E, F, W2> where W2: for<'writer> MakeWriter<'writer> + 'static, @@ -1088,13 +1056,89 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// /// [capturing]: /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output - /// [`TestWriter`]: writer/struct.TestWriter.html + /// [`TestWriter`]: writer::TestWriter pub fn with_test_writer(self) -> SubscriberBuilder<N, E, F, TestWriter> { SubscriberBuilder { filter: self.filter, inner: self.inner.with_writer(TestWriter::default()), } } + + /// Updates the event formatter by applying a function to the existing event formatter. + /// + /// This sets the event formatter that the subscriber being built will use to record fields. + /// + /// # Examples + /// + /// Updating an event formatter: + /// + /// ```rust + /// let subscriber = tracing_subscriber::fmt() + /// .map_event_format(|e| e.compact()) + /// .finish(); + /// ``` + pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> SubscriberBuilder<N, E2, F, W> + where + E2: FormatEvent<Registry, N> + 'static, + N: for<'writer> FormatFields<'writer> + 'static, + W: for<'writer> MakeWriter<'writer> + 'static, + { + SubscriberBuilder { + filter: self.filter, + inner: self.inner.map_event_format(f), + } + } + + /// Updates the field formatter by applying a function to the existing field formatter. + /// + /// This sets the field formatter that the subscriber being built will use to record fields. + /// + /// # Examples + /// + /// Updating a field formatter: + /// + /// ```rust + /// use tracing_subscriber::field::MakeExt; + /// let subscriber = tracing_subscriber::fmt() + /// .map_fmt_fields(|f| f.debug_alt()) + /// .finish(); + /// ``` + pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> SubscriberBuilder<N2, E, F, W> + where + N2: for<'writer> FormatFields<'writer> + 'static, + { + SubscriberBuilder { + filter: self.filter, + inner: self.inner.map_fmt_fields(f), + } + } + + /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`]. + /// + /// This sets the [`MakeWriter`] that the subscriber being built will use to write events. + /// + /// # Examples + /// + /// Redirect output to stderr if level is <= WARN: + /// + /// ```rust + /// use tracing::Level; + /// use tracing_subscriber::fmt::{self, writer::MakeWriterExt}; + /// + /// let stderr = std::io::stderr.with_max_level(Level::WARN); + /// let layer = tracing_subscriber::fmt() + /// .map_writer(move |w| stderr.or_else(w)) + /// .finish(); + /// ``` + pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> SubscriberBuilder<N, E, F, W2> + where + W2: for<'writer> MakeWriter<'writer> + 'static, + { + SubscriberBuilder { + filter: self.filter, + inner: self.inner.map_writer(f), + } + } } /// Install a global tracing subscriber that listens for events and @@ -1121,35 +1165,69 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> { /// /// [`LogTracer`]: /// https://docs.rs/tracing-log/0.1.0/tracing_log/struct.LogTracer.html -/// [`RUST_LOG` environment variable]: -/// ../filter/struct.EnvFilter.html#associatedconstant.DEFAULT_ENV +/// [`RUST_LOG` environment variable]: crate::filter::EnvFilter::DEFAULT_ENV pub fn try_init() -> Result<(), Box<dyn Error + Send + Sync + 'static>> { let builder = Subscriber::builder(); #[cfg(feature = "env-filter")] let builder = builder.with_env_filter(crate::EnvFilter::from_default_env()); - builder.try_init() + // If `env-filter` is disabled, remove the default max level filter from the + // subscriber; it will be added to the `Targets` filter instead if no filter + // is set in `RUST_LOG`. + // Replacing the default `LevelFilter` with an `EnvFilter` would imply this, + // but we can't replace the builder's filter with a `Targets` filter yet. + #[cfg(not(feature = "env-filter"))] + let builder = builder.with_max_level(LevelFilter::TRACE); + + let subscriber = builder.finish(); + #[cfg(not(feature = "env-filter"))] + let subscriber = { + use crate::{filter::Targets, layer::SubscriberExt}; + use std::{env, str::FromStr}; + let targets = match env::var("RUST_LOG") { + Ok(var) => Targets::from_str(&var) + .map_err(|e| { + eprintln!("Ignoring `RUST_LOG={:?}`: {}", var, e); + }) + .unwrap_or_default(), + Err(env::VarError::NotPresent) => { + Targets::new().with_default(Subscriber::DEFAULT_MAX_LEVEL) + } + Err(e) => { + eprintln!("Ignoring `RUST_LOG`: {}", e); + Targets::new().with_default(Subscriber::DEFAULT_MAX_LEVEL) + } + }; + subscriber.with(targets) + }; + + subscriber.try_init().map_err(Into::into) } /// Install a global tracing subscriber that listens for events and /// filters based on the value of the [`RUST_LOG` environment variable]. /// +/// The configuration of the subscriber initialized by this function +/// depends on what [feature flags](crate#feature-flags) are enabled. +/// /// If the `tracing-log` feature is enabled, this will also install /// the LogTracer to convert `Log` records into `tracing` `Event`s. /// -/// This is shorthand for +/// If the `env-filter` feature is enabled, this is shorthand for /// /// ```rust -/// tracing_subscriber::fmt().init() +/// # use tracing_subscriber::EnvFilter; +/// tracing_subscriber::fmt() +/// .with_env_filter(EnvFilter::from_default_env()) +/// .init(); /// ``` /// /// # Panics /// Panics if the initialization was unsuccessful, likely because a /// global subscriber was already installed by another call to `try_init`. /// -/// [`RUST_LOG` environment variable]: -/// ../filter/struct.EnvFilter.html#associatedconstant.DEFAULT_ENV +/// [`RUST_LOG` environment variable]: crate::filter::EnvFilter::DEFAULT_ENV pub fn init() { try_init().expect("Unable to install global subscriber") } diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/time/datetime.rs b/vendor/tracing-subscriber/src/fmt/time/datetime.rs index 531331687..531331687 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/time/datetime.rs +++ b/vendor/tracing-subscriber/src/fmt/time/datetime.rs diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/time/mod.rs b/vendor/tracing-subscriber/src/fmt/time/mod.rs index 621df16e4..e5b7c83b0 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/time/mod.rs +++ b/vendor/tracing-subscriber/src/fmt/time/mod.rs @@ -12,9 +12,13 @@ mod time_crate; pub use time_crate::UtcTime; #[cfg(feature = "local-time")] -#[cfg_attr(docsrs, doc(cfg(feature = "local-time")))] +#[cfg_attr(docsrs, doc(cfg(unsound_local_offset, feature = "local-time")))] pub use time_crate::LocalTime; +#[cfg(feature = "time")] +#[cfg_attr(docsrs, doc(cfg(feature = "time")))] +pub use time_crate::OffsetTime; + /// A type that can measure and format the current time. /// /// This trait is used by `Format` to include a timestamp with each `Event` when it is logged. @@ -26,7 +30,7 @@ pub use time_crate::LocalTime; /// /// The full list of provided implementations can be found in [`time`]. /// -/// [`time`]: ./index.html +/// [`time`]: self pub trait FormatTime { /// Measure and write out the current time. /// diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/writer.rs b/vendor/tracing-subscriber/src/fmt/writer.rs index 0974891f7..3fe945566 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/writer.rs +++ b/vendor/tracing-subscriber/src/fmt/writer.rs @@ -1,6 +1,6 @@ //! Abstractions for creating [`io::Write`] instances. //! -//! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [`io::Write`]: std::io::Write use std::{ fmt, io::{self, Write}, @@ -96,8 +96,8 @@ use tracing_core::Metadata; pub trait MakeWriter<'a> { /// The concrete [`io::Write`] implementation returned by [`make_writer`]. /// - /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html - /// [`make_writer`]: #tymethod.make_writer + /// [`io::Write`]: std::io::Write + /// [`make_writer`]: MakeWriter::make_writer type Writer: io::Write; /// Returns an instance of [`Writer`]. @@ -109,7 +109,7 @@ pub trait MakeWriter<'a> { /// creating a [`io::Write`] instance is expensive, be sure to cache it when implementing /// [`MakeWriter`] to improve performance. /// - /// [`Writer`]: #associatedtype.Writer + /// [`Writer`]: MakeWriter::Writer /// [`fmt::Layer`]: crate::fmt::Layer /// [`fmt::Subscriber`]: crate::fmt::Subscriber /// [`io::Write`]: std::io::Write @@ -501,13 +501,13 @@ pub trait MakeWriterExt<'a>: MakeWriter<'a> { /// Writing to [`io::stdout`] and [`io::stderr`] produces the same results as using /// [`libtest`'s `--nocapture` option][nocapture] which may make the results look unreadable. /// -/// [`fmt::Subscriber`]: ../struct.Subscriber.html -/// [`fmt::Layer`]: ../struct.Layer.html +/// [`fmt::Subscriber`]: super::Subscriber +/// [`fmt::Layer`]: super::Layer /// [capturing]: https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output /// [nocapture]: https://doc.rust-lang.org/cargo/commands/cargo-test.html -/// [`io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html -/// [`io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html -/// [`print!`]: https://doc.rust-lang.org/std/macro.print.html +/// [`io::stdout`]: std::io::stdout +/// [`io::stderr`]: std::io::stderr +/// [`print!`]: std::print! #[derive(Default, Debug)] pub struct TestWriter { _p: (), @@ -646,10 +646,9 @@ pub struct Tee<A, B> { /// requires the `Writer` type to implement [`io::Write`], it's necessary to add /// a newtype that forwards the trait implementation. /// -/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -/// [`MutexGuard`]: https://doc.rust-lang.org/std/sync/struct.MutexGuard.html -/// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html -/// [`MakeWriter`]: trait.MakeWriter.html +/// [`io::Write`]: std::io::Write +/// [`MutexGuard`]: std::sync::MutexGuard +/// [`Mutex`]: std::sync::Mutex #[derive(Debug)] pub struct MutexGuardWriter<'a, W>(MutexGuard<'a, W>); @@ -689,7 +688,7 @@ where { type Writer = &'a W; fn make_writer(&'a self) -> Self::Writer { - &*self + self } } @@ -734,7 +733,6 @@ impl<'a> MakeWriter<'a> for TestWriter { impl BoxMakeWriter { /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`]. /// - /// [`MakeWriter`]: trait.MakeWriter.html pub fn new<M>(make_writer: M) -> Self where M: for<'a> MakeWriter<'a> + Send + Sync + 'static, @@ -1025,6 +1023,8 @@ impl<A, B> Tee<A, B> { /// outputs. /// /// See the documentation for [`MakeWriterExt::and`] for details. + /// + /// [writers]: std::io::Write pub fn new(a: A, b: B) -> Self { Self { a, b } } |