diff --git a/tracing-error/src/subscriber.rs b/tracing-error/src/subscriber.rs index 8874401a22..2e81d2d921 100644 --- a/tracing-error/src/subscriber.rs +++ b/tracing-error/src/subscriber.rs @@ -53,10 +53,9 @@ where if span.extensions().get::>().is_some() { return; } - let mut fields = String::new(); - if self.format.format_fields(&mut fields, attrs).is_ok() { - span.extensions_mut() - .insert(FormattedFields::::new(fields)); + let mut fields = FormattedFields::::new(String::new()); + if self.format.format_fields(fields.as_writer(), attrs).is_ok() { + span.extensions_mut().insert(fields); } } diff --git a/tracing-subscriber/src/fmt/fmt_subscriber.rs b/tracing-subscriber/src/fmt/fmt_subscriber.rs index 23209b949f..c41daedc3d 100644 --- a/tracing-subscriber/src/fmt/fmt_subscriber.rs +++ b/tracing-subscriber/src/fmt/fmt_subscriber.rs @@ -485,37 +485,46 @@ where /// /// [extensions]: crate::registry::Extensions #[derive(Default)] -pub struct FormattedFields { - _format_event: PhantomData, +pub struct FormattedFields { + _format_fields: PhantomData, /// The formatted fields of a span. pub fields: String, } -impl FormattedFields { +impl FormattedFields { /// Returns a new `FormattedFields`. pub fn new(fields: String) -> Self { Self { fields, - _format_event: PhantomData, + _format_fields: PhantomData, } } + + /// Returns a new [`format::Writer`] for writing to this `FormattedFields`. + /// + /// The returned [`format::Writer`] can be used with the + /// [`FormatFields::format_fields`] method. + pub fn as_writer(&mut self) -> format::Writer<'_> { + format::Writer::new(&mut self.fields) + } } -impl fmt::Debug for FormattedFields { +impl fmt::Debug for FormattedFields { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FormattedFields") .field("fields", &self.fields) + .field("formatter", &format_args!("{}", std::any::type_name::())) .finish() } } -impl fmt::Display for FormattedFields { +impl fmt::Display for FormattedFields { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.fields) + fmt::Display::fmt(&self.fields, f) } } -impl Deref for FormattedFields { +impl Deref for FormattedFields { type Target = String; fn deref(&self) -> &Self::Target { &self.fields @@ -552,13 +561,13 @@ where let mut extensions = span.extensions_mut(); if extensions.get_mut::>().is_none() { - let mut buf = String::new(); - if self.fmt_fields.format_fields(&mut buf, attrs).is_ok() { - let fmt_fields = FormattedFields { - fields: buf, - _format_event: PhantomData::, - }; - extensions.insert(fmt_fields); + let mut fields = FormattedFields::::new(String::new()); + if self + .fmt_fields + .format_fields(fields.as_writer(), attrs) + .is_ok() + { + extensions.insert(fields); } } @@ -581,19 +590,18 @@ where fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, C>) { let span = ctx.span(id).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); - if let Some(FormattedFields { ref mut fields, .. }) = - extensions.get_mut::>() - { + if let Some(fields) = extensions.get_mut::>() { let _ = self.fmt_fields.add_fields(fields, values); - } else { - let mut buf = String::new(); - if self.fmt_fields.format_fields(&mut buf, values).is_ok() { - let fmt_fields = FormattedFields { - fields: buf, - _format_event: PhantomData::, - }; - extensions.insert(fmt_fields); - } + return; + } + + let mut fields = FormattedFields::::new(String::new()); + if self + .fmt_fields + .format_fields(fields.as_writer(), values) + .is_ok() + { + extensions.insert(fields); } } @@ -695,7 +703,11 @@ where }; let ctx = self.make_ctx(ctx); - if self.fmt_event.format_event(&ctx, &mut buf, event).is_ok() { + if self + .fmt_event + .format_event(&ctx, format::Writer::new(&mut buf), event) + .is_ok() + { let mut writer = self.make_writer.make_writer_for(event.metadata()); let _ = io::Write::write_all(&mut writer, buf.as_bytes()); } @@ -738,7 +750,7 @@ where { fn format_fields( &self, - writer: &'writer mut dyn fmt::Write, + writer: format::Writer<'writer>, fields: R, ) -> fmt::Result { self.fmt_fields.format_fields(writer, fields) diff --git a/tracing-subscriber/src/fmt/format/json.rs b/tracing-subscriber/src/fmt/format/json.rs index 98beff6f46..3c085855fc 100644 --- a/tracing-subscriber/src/fmt/format/json.rs +++ b/tracing-subscriber/src/fmt/format/json.rs @@ -1,4 +1,4 @@ -use super::{Format, FormatEvent, FormatFields, FormatTime}; +use super::{Format, FormatEvent, FormatFields, FormatTime, Writer}; use crate::{ field::{RecordFields, VisitOutput}, fmt::{ @@ -185,14 +185,14 @@ where fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result where C: Collect + for<'a> LookupSpan<'a>, { let mut timestamp = String::new(); - self.timer.format_time(&mut timestamp)?; + self.timer.format_time(&mut Writer::new(&mut timestamp))?; #[cfg(feature = "tracing-log")] let normalized_meta = event.normalized_metadata(); @@ -202,7 +202,7 @@ where let meta = event.metadata(); let mut visit = || { - let mut serializer = Serializer::new(WriteAdaptor::new(writer)); + let mut serializer = Serializer::new(WriteAdaptor::new(&mut writer)); let mut serializer = serializer.serialize_map(None)?; @@ -318,12 +318,8 @@ impl Default for JsonFields { impl<'a> FormatFields<'a> for JsonFields { /// Format the provided `fields` to the provided `writer`, returning a result. - fn format_fields( - &self, - writer: &'a mut dyn fmt::Write, - fields: R, - ) -> fmt::Result { - let mut v = JsonVisitor::new(writer); + fn format_fields(&self, mut writer: Writer<'_>, fields: R) -> fmt::Result { + let mut v = JsonVisitor::new(&mut writer); fields.record(&mut v); v.finish() } @@ -333,38 +329,44 @@ impl<'a> FormatFields<'a> for JsonFields { /// By default, this appends a space to the current set of fields if it is /// non-empty, and then calls `self.format_fields`. If different behavior is /// required, the default implementation of this method can be overridden. - fn add_fields(&self, current: &'a mut String, fields: &Record<'_>) -> fmt::Result { - if !current.is_empty() { - // If fields were previously recorded on this span, we need to parse - // the current set of fields as JSON, add the new fields, and - // re-serialize them. Otherwise, if we just appended the new fields - // to a previously serialized JSON object, we would end up with - // malformed JSON. - // - // XXX(eliza): this is far from efficient, but unfortunately, it is - // necessary as long as the JSON formatter is implemented on top of - // an interface that stores all formatted fields as strings. - // - // We should consider reimplementing the JSON formatter as a - // separate layer, rather than a formatter for the `fmt` layer — - // then, we could store fields as JSON values, and add to them - // without having to parse and re-serialize. - let mut new = String::new(); - let map: BTreeMap<&'_ str, serde_json::Value> = - serde_json::from_str(current).map_err(|_| fmt::Error)?; - let mut v = JsonVisitor::new(&mut new); - v.values = map; - fields.record(&mut v); - v.finish()?; - *current = new; - } else { + fn add_fields( + &self, + current: &'a mut FormattedFields, + fields: &Record<'_>, + ) -> fmt::Result { + if current.is_empty() { // If there are no previously recorded fields, we can just reuse the // existing string. - let mut v = JsonVisitor::new(current); + let mut writer = current.as_writer(); + let mut v = JsonVisitor::new(&mut writer); fields.record(&mut v); v.finish()?; + return Ok(()); } + // If fields were previously recorded on this span, we need to parse + // the current set of fields as JSON, add the new fields, and + // re-serialize them. Otherwise, if we just appended the new fields + // to a previously serialized JSON object, we would end up with + // malformed JSON. + // + // XXX(eliza): this is far from efficient, but unfortunately, it is + // necessary as long as the JSON formatter is implemented on top of + // an interface that stores all formatted fields as strings. + // + // We should consider reimplementing the JSON formatter as a + // separate layer, rather than a formatter for the `fmt` layer — + // then, we could store fields as JSON values, and add to them + // without having to parse and re-serialize. + let mut new = String::new(); + let map: BTreeMap<&'_ str, serde_json::Value> = + serde_json::from_str(current).map_err(|_| fmt::Error)?; + let mut v = JsonVisitor::new(&mut new); + v.values = map; + fields.record(&mut v); + v.finish()?; + current.fields = new; + Ok(()) } } @@ -484,7 +486,7 @@ mod test { struct MockTime; impl FormatTime for MockTime { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { write!(w, "fake time") } } diff --git a/tracing-subscriber/src/fmt/format/mod.rs b/tracing-subscriber/src/fmt/format/mod.rs index 458fed7f8d..c8ca8f8b1d 100644 --- a/tracing-subscriber/src/fmt/format/mod.rs +++ b/tracing-subscriber/src/fmt/format/mod.rs @@ -7,10 +7,7 @@ use crate::{ registry::Scope, }; -use std::{ - fmt::{self, Write}, - marker::PhantomData, -}; +use std::{fmt, marker::PhantomData}; use tracing_core::{ field::{self, Field, Visit}, span, Collect, Event, Level, @@ -36,7 +33,7 @@ pub use pretty::*; use fmt::{Debug, Display}; -/// A type that can format a tracing `Event` for a `fmt::Write`. +/// A type that can format a tracing [`Event`] to a [`Writer`]. /// /// `FormatEvent` is primarily used in the context of [`fmt::Collector`] or [`fmt::Subscriber`]. /// Each time an event is dispatched to [`fmt::Collector`] or [`fmt::Subscriber`], @@ -48,9 +45,13 @@ use fmt::{Debug, Display}; /// # Examples /// /// ```rust -/// use std::fmt::{self, Write}; +/// use std::fmt; /// use tracing_core::{Collect, Event}; -/// use tracing_subscriber::fmt::{FormatEvent, FormatFields, FmtContext, FormattedFields}; +/// use tracing_subscriber::fmt::{ +/// format::{self, FormatEvent, FormatFields}, +/// FmtContext, +/// FormattedFields, +/// }; /// use tracing_subscriber::registry::LookupSpan; /// /// struct MyFormatter; @@ -63,7 +64,7 @@ use fmt::{Debug, Display}; /// fn format_event( /// &self, /// ctx: &FmtContext<'_, C, N>, -/// writer: &mut dyn fmt::Write, +/// mut writer: format::Writer<'_>, /// event: &Event<'_>, /// ) -> fmt::Result { /// // Write level and target @@ -100,7 +101,7 @@ use fmt::{Debug, Display}; /// })?; /// /// // Write fields on the event -/// ctx.field_format().format_fields(writer, event)?; +/// ctx.field_format().format_fields(writer.by_ref(), event)?; /// /// writeln!(writer) /// } @@ -115,22 +116,23 @@ use fmt::{Debug, Display}; /// /// [`fmt::Collector`]: super::Collector /// [`fmt::Subscriber`]: super::Subscriber +/// [`Event`]: tracing::Event pub trait FormatEvent where C: Collect + for<'a> LookupSpan<'a>, N: for<'a> FormatFields<'a> + 'static, { - /// Write a log message for `Event` in `Context` to the given `Write`. + /// Write a log message for `Event` in `Context` to the given [`Writer`]. fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result; } impl FormatEvent - for fn(ctx: &FmtContext<'_, C, N>, &mut dyn fmt::Write, &Event<'_>) -> fmt::Result + for fn(ctx: &FmtContext<'_, C, N>, Writer<'_>, &Event<'_>) -> fmt::Result where C: Collect + for<'a> LookupSpan<'a>, N: for<'a> FormatFields<'a> + 'static, @@ -138,13 +140,13 @@ where fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { (*self)(ctx, writer, event) } } -/// A type that can format a [set of fields] to a `fmt::Write`. +/// A type that can format a [set of fields] to a [`Writer`]. /// /// `FormatFields` is primarily used in the context of [`fmt::Subscriber`]. Each /// time a span or event with fields is recorded, the subscriber will format @@ -153,23 +155,23 @@ where /// [set of fields]: RecordFields /// [`fmt::Subscriber`]: super::Subscriber pub trait FormatFields<'writer> { - /// Format the provided `fields` to the provided `writer`, returning a result. - fn format_fields( - &self, - writer: &'writer mut dyn fmt::Write, - fields: R, - ) -> fmt::Result; + /// Format the provided `fields` to the provided [`Writer`], returning a result. + fn format_fields(&self, writer: Writer<'writer>, fields: R) -> fmt::Result; /// Record additional field(s) on an existing span. /// /// By default, this appends a space to the current set of fields if it is /// non-empty, and then calls `self.format_fields`. If different behavior is /// required, the default implementation of this method can be overridden. - fn add_fields(&self, current: &'writer mut String, fields: &span::Record<'_>) -> fmt::Result { - if !current.is_empty() { - current.push(' '); + fn add_fields( + &self, + current: &'writer mut FormattedFields, + fields: &span::Record<'_>, + ) -> fmt::Result { + if !current.fields.is_empty() { + current.fields.push(' '); } - self.format_fields(current, fields) + self.format_fields(current.as_writer(), fields) } } @@ -209,11 +211,29 @@ pub fn json() -> Format { /// pub fn debug_fn(f: F) -> FieldFn where - F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result + Clone, + F: Fn(&mut Writer<'_>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone, { FieldFn(f) } +/// A writer to which formatted representations of spans and events are written. +/// +/// This type is provided as input to the [`FormatEvent::format_event`] and +/// [`FormatFields::format_fields`] methods, which will write formatted +/// representations of [`Event`]s and [fields] to the `Writer`. +/// +/// This type implements the [`std::fmt::Write`] trait, allowing it to be used +/// with any function that takes an instance of [`std::fmt::Write`]. +/// Additionally, it can be used with the standard library's [`std::write!`] and +/// [`std::writeln!`] macros. +/// +/// Additionally, a `Writer` may expose additional `tracing`-specific +/// information to the formatter implementation. +pub struct Writer<'writer> { + writer: &'writer mut dyn fmt::Write, + // TODO(eliza): add ANSI support +} + /// A [`FormatFields`] implementation that formats fields by calling a function /// or closure. /// @@ -225,7 +245,7 @@ pub struct FieldFn(F); /// [`MakeVisitor`]: super::super::field::MakeVisitor pub struct FieldFnVisitor<'a, F> { f: F, - writer: &'a mut dyn fmt::Write, + writer: Writer<'a>, result: fmt::Result, } /// Marker for `Format` that indicates that the compact log format should be used. @@ -259,6 +279,115 @@ pub struct Format { pub(crate) display_thread_name: bool, } +// === impl Writer === + +impl<'writer> Writer<'writer> { + // TODO(eliza): consider making this a public API? + // We may not want to do that if we choose to expose specialized + // constructors instead (e.g. `from_string` that stores whether the string + // is empty...?) + pub(crate) fn new(writer: &'writer mut impl fmt::Write) -> Self { + Self { + writer: writer as &mut dyn fmt::Write, + } + } + + /// Return a new `Writer` that mutably borrows `self`. + /// + /// This can be used to temporarily borrow a `Writer` to pass a new `Writer` + /// to a function that takes a `Writer` by value, allowing the original writer + /// to still be used once that function returns. + pub fn by_ref(&mut self) -> Writer<'_> { + Writer::new(self) + } + + /// Writes a string slice into this `Writer`, returning whether the write succeeded. + /// + /// This method can only succeed if the entire string slice was successfully + /// written, and this method will not return until all data has been written + /// or an error occurs. + /// + /// This is identical to calling the [`write_str` method] from the `Writer`'s + /// [`std::fmt::Write`] implementation. However, it is also provided as an + /// inherent method, so that `Writer`s can be used without needing to import the + /// [`std::fmt::Write`] trait. + /// + /// # Errors + /// + /// This function will return an instance of [`std::fmt::Error`] on error. + /// + /// [`write_str` method]: std::fmt::Write::write_str + #[inline] + pub fn write_str(&mut self, s: &str) -> fmt::Result { + self.writer.write_str(s) + } + + /// Writes a [`char`] into this writer, returning whether the write succeeded. + /// + /// A single [`char`] may be encoded as more than one byte. + /// This method can only succeed if the entire byte sequence was successfully + /// written, and this method will not return until all data has been + /// written or an error occurs. + /// + /// This is identical to calling the [`write_char` method] from the `Writer`'s + /// [`std::fmt::Write`] implementation. However, it is also provided as an + /// inherent method, so that `Writer`s can be used without needing to import the + /// [`std::fmt::Write`] trait. + /// + /// # Errors + /// + /// This function will return an instance of [`std::fmt::Error`] on error. + /// + /// [`write_char` method]: std::fmt::Write::write_char + #[inline] + pub fn write_char(&mut self, c: char) -> fmt::Result { + self.writer.write_char(c) + } + + /// Glue for usage of the [`write!`] macro with `Wrriter`s. + /// + /// This method should generally not be invoked manually, but rather through + /// the [`write!`] macro itself. + /// + /// This is identical to calling the [`write_fmt` method] from the `Writer`'s + /// [`std::fmt::Write`] implementation. However, it is also provided as an + /// inherent method, so that `Writer`s can be used with the [`write!` macro] + /// without needing to import the + /// [`std::fmt::Write`] trait. + /// + /// [`write_fmt` method]: std::fmt::Write::write_fmt + pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { + self.writer.write_fmt(args) + } +} + +impl fmt::Write for Writer<'_> { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + Writer::write_str(self, s) + } + + #[inline] + fn write_char(&mut self, c: char) -> fmt::Result { + Writer::write_char(self, c) + } + + #[inline] + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { + Writer::write_fmt(self, args) + } +} + +impl fmt::Debug for Writer<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Writer") + .field("writer", &format_args!("<&mut dyn fmt::Write>")) + .finish() + } +} + +// === impl Format === + impl Default for Format { fn default() -> Self { Format { @@ -464,7 +593,7 @@ impl Format { } #[inline] - fn format_timestamp(&self, writer: &mut dyn fmt::Write) -> fmt::Result + fn format_timestamp(&self, writer: &mut Writer<'_>) -> fmt::Result where T: FormatTime, { @@ -553,7 +682,7 @@ where fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { #[cfg(feature = "tracing-log")] @@ -563,8 +692,8 @@ where #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - self.format_timestamp(writer)?; - self.format_level(*meta.level(), writer)?; + self.format_timestamp(&mut writer)?; + self.format_level(*meta.level(), &mut writer)?; if self.display_thread_name { let current_thread = std::thread::current(); @@ -610,7 +739,7 @@ where write!(writer, "{}: ", meta.target())?; } - ctx.format_fields(writer, event)?; + ctx.format_fields(writer.by_ref(), event)?; writeln!(writer) } } @@ -624,7 +753,7 @@ where fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { #[cfg(feature = "tracing-log")] @@ -634,8 +763,8 @@ where #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - self.format_timestamp(writer)?; - self.format_level(*meta.level(), writer)?; + self.format_timestamp(&mut writer)?; + self.format_level(*meta.level(), &mut writer)?; if self.display_thread_name { let current_thread = std::thread::current(); @@ -667,7 +796,7 @@ where write!(writer, "{}:", target)?; } - ctx.format_fields(writer, event)?; + ctx.format_fields(writer.by_ref(), event)?; #[cfg(feature = "ansi")] let dimmed = if self.ansi { @@ -697,22 +826,18 @@ where } // === impl FormatFields === - impl<'writer, M> FormatFields<'writer> for M where - M: MakeOutput<&'writer mut dyn fmt::Write, fmt::Result>, + M: MakeOutput, fmt::Result>, M::Visitor: VisitFmt + VisitOutput, { - fn format_fields( - &self, - writer: &'writer mut dyn fmt::Write, - fields: R, - ) -> fmt::Result { + fn format_fields(&self, writer: Writer<'writer>, fields: R) -> fmt::Result { let mut v = self.make_visitor(writer); fields.record(&mut v); v.finish() } } + /// The default [`FormatFields`] implementation. /// #[derive(Debug)] @@ -726,8 +851,9 @@ pub struct DefaultFields { /// /// [visitor]: super::super::field::Visit /// [`MakeVisitor`]: super::super::field::MakeVisitor +#[derive(Debug)] pub struct DefaultVisitor<'a> { - writer: &'a mut dyn Write, + writer: Writer<'a>, is_empty: bool, result: fmt::Result, } @@ -746,11 +872,11 @@ impl Default for DefaultFields { } } -impl<'a> MakeVisitor<&'a mut dyn Write> for DefaultFields { +impl<'a> MakeVisitor> for DefaultFields { type Visitor = DefaultVisitor<'a>; #[inline] - fn make_visitor(&self, target: &'a mut dyn Write) -> Self::Visitor { + fn make_visitor(&self, target: Writer<'a>) -> Self::Visitor { DefaultVisitor::new(target, true) } } @@ -764,7 +890,7 @@ impl<'a> DefaultVisitor<'a> { /// - `writer`: the writer to format to. /// - `is_empty`: whether or not any fields have been previously written to /// that writer. - pub fn new(writer: &'a mut dyn Write, is_empty: bool) -> Self { + pub fn new(writer: Writer<'a>, is_empty: bool) -> Self { Self { writer, is_empty, @@ -830,17 +956,7 @@ impl<'a> crate::field::VisitOutput for DefaultVisitor<'a> { impl<'a> crate::field::VisitFmt for DefaultVisitor<'a> { fn writer(&mut self) -> &mut dyn fmt::Write { - self.writer - } -} - -impl<'a> fmt::Debug for DefaultVisitor<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DefaultVisitor") - .field("writer", &format_args!("")) - .field("is_empty", &self.is_empty) - .field("result", &self.result) - .finish() + &mut self.writer } } @@ -998,13 +1114,13 @@ impl<'a, F: LevelNames> fmt::Display for FmtLevel { // === impl FieldFn === -impl<'a, F> MakeVisitor<&'a mut dyn fmt::Write> for FieldFn +impl<'a, F> MakeVisitor> for FieldFn where - F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result + Clone, + F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone, { type Visitor = FieldFnVisitor<'a, F>; - fn make_visitor(&self, writer: &'a mut dyn fmt::Write) -> Self::Visitor { + fn make_visitor(&self, writer: Writer<'a>) -> Self::Visitor { FieldFnVisitor { writer, f: self.0.clone(), @@ -1015,7 +1131,7 @@ where impl<'a, F> Visit for FieldFnVisitor<'a, F> where - F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result, + F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result, { fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { if self.result.is_ok() { @@ -1026,7 +1142,7 @@ where impl<'a, F> VisitOutput for FieldFnVisitor<'a, F> where - F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result, + F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result, { fn finish(self) -> fmt::Result { self.result @@ -1035,18 +1151,18 @@ where impl<'a, F> VisitFmt for FieldFnVisitor<'a, F> where - F: Fn(&mut dyn fmt::Write, &Field, &dyn fmt::Debug) -> fmt::Result, + F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result, { fn writer(&mut self) -> &mut dyn fmt::Write { - &mut *self.writer + &mut self.writer } } impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FieldFnVisitor") - .field("f", &format_args!("")) - .field("writer", &format_args!("")) + .field("f", &format_args!("{}", std::any::type_name::())) + .field("writer", &self.writer) .field("result", &self.result) .finish() } @@ -1217,12 +1333,12 @@ pub(super) mod test { dispatch::{set_default, Dispatch}, }; - use super::{FmtSpan, TimingDisplay}; + use super::{FmtSpan, TimingDisplay, Writer}; use std::fmt; pub(crate) struct MockTime; impl FormatTime for MockTime { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { write!(w, "fake time") } } diff --git a/tracing-subscriber/src/fmt/format/pretty.rs b/tracing-subscriber/src/fmt/format/pretty.rs index a22fdd58a9..78acbcc04e 100644 --- a/tracing-subscriber/src/fmt/format/pretty.rs +++ b/tracing-subscriber/src/fmt/format/pretty.rs @@ -94,7 +94,7 @@ where fn format_event( &self, ctx: &FmtContext<'_, C, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { #[cfg(feature = "tracing-log")] @@ -103,9 +103,9 @@ where let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - write!(writer, " ")?; + write!(&mut writer, " ")?; - self.format_timestamp(writer)?; + self.format_timestamp(&mut writer)?; let style = if self.display_level && self.ansi { Pretty::style_for(meta.level()) @@ -114,7 +114,7 @@ where }; if self.display_level { - self.format_level(*meta.level(), writer)?; + self.format_level(*meta.level(), &mut writer)?; } if self.display_target { @@ -127,7 +127,7 @@ where target_style.infix(style) )?; } - let mut v = PrettyVisitor::new(writer, true) + let mut v = PrettyVisitor::new(&mut writer, true) .with_style(style) .with_ansi(self.ansi); event.record(&mut v); @@ -221,17 +221,22 @@ where impl<'writer> FormatFields<'writer> for Pretty { fn format_fields( &self, - writer: &'writer mut dyn fmt::Write, + mut writer: Writer<'writer>, fields: R, ) -> fmt::Result { - let mut v = PrettyVisitor::new(writer, true); + let mut v = PrettyVisitor::new(&mut writer, false); fields.record(&mut v); v.finish() } - fn add_fields(&self, current: &'writer mut String, fields: &span::Record<'_>) -> fmt::Result { + fn add_fields( + &self, + current: &'writer mut FormattedFields, + fields: &span::Record<'_>, + ) -> fmt::Result { let empty = current.is_empty(); - let mut v = PrettyVisitor::new(current, empty); + let mut writer = current.as_writer(); + let mut v = PrettyVisitor::new(&mut writer, empty); fields.record(&mut v); v.finish() } @@ -257,12 +262,12 @@ impl PrettyFields { } } -impl<'a> MakeVisitor<&'a mut dyn Write> for PrettyFields { +impl<'a> MakeVisitor> for PrettyFields { type Visitor = PrettyVisitor<'a>; #[inline] - fn make_visitor(&self, target: &'a mut dyn Write) -> Self::Visitor { - PrettyVisitor::new(target, true).with_ansi(self.ansi) + fn make_visitor(&self, target: Writer<'a>) -> Self::Visitor { + PrettyVisitor::new(target.writer, true).with_ansi(self.ansi) } } diff --git a/tracing-subscriber/src/fmt/time/mod.rs b/tracing-subscriber/src/fmt/time/mod.rs index 52e789fc60..5e253aa107 100644 --- a/tracing-subscriber/src/fmt/time/mod.rs +++ b/tracing-subscriber/src/fmt/time/mod.rs @@ -1,4 +1,5 @@ //! Formatters for event timestamps. +use crate::fmt::format::Writer; use std::fmt; use std::time::Instant; @@ -29,7 +30,7 @@ pub trait FormatTime { /// When `format_time` is called, implementors should get the current time using their desired /// mechanism, and write it out to the given `fmt::Write`. Implementors must insert a trailing /// space themselves if they wish to separate the time from subsequent log message text. - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result; + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result; } /// Returns a new `SystemTime` timestamp provider. @@ -69,19 +70,19 @@ impl<'a, F> FormatTime for &'a F where F: FormatTime, { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { (*self).format_time(w) } } impl FormatTime for () { - fn format_time(&self, _: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, _: &mut Writer<'_>) -> fmt::Result { Ok(()) } } -impl FormatTime for fn(&mut dyn fmt::Write) -> fmt::Result { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { +impl FormatTime for fn(&mut Writer<'_>) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { (*self)(w) } } @@ -113,7 +114,7 @@ impl From for Uptime { } impl FormatTime for SystemTime { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { write!( w, "{}", @@ -123,7 +124,7 @@ impl FormatTime for SystemTime { } impl FormatTime for Uptime { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { let e = self.epoch.elapsed(); write!(w, "{:4}.{:09}s", e.as_secs(), e.subsec_nanos()) } diff --git a/tracing-subscriber/src/fmt/time/time_crate.rs b/tracing-subscriber/src/fmt/time/time_crate.rs index 360764f5bb..bb5fdd0ed4 100644 --- a/tracing-subscriber/src/fmt/time/time_crate.rs +++ b/tracing-subscriber/src/fmt/time/time_crate.rs @@ -1,4 +1,4 @@ -use crate::fmt::{time::FormatTime, writer::WriteAdaptor}; +use crate::fmt::{format::Writer, time::FormatTime, writer::WriteAdaptor}; use std::fmt; use time::{format_description::well_known, formatting::Formattable, OffsetDateTime}; @@ -134,7 +134,7 @@ impl FormatTime for LocalTime where F: Formattable, { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?; format_datetime(now, w, &self.format) } @@ -250,7 +250,7 @@ impl FormatTime for UtcTime where F: Formattable, { - fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { format_datetime(OffsetDateTime::now_utc(), w, &self.format) } } @@ -266,7 +266,7 @@ where fn format_datetime( now: OffsetDateTime, - into: &mut dyn fmt::Write, + into: &mut Writer<'_>, fmt: &impl Formattable, ) -> fmt::Result { let mut into = WriteAdaptor::new(into);