diff --git a/tracing-error/src/layer.rs b/tracing-error/src/layer.rs index d2ddf65b2f..8a26e8cbea 100644 --- a/tracing-error/src/layer.rs +++ b/tracing-error/src/layer.rs @@ -45,10 +45,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_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index 9052e30a08..90269a7732 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -533,37 +533,46 @@ where /// /// [extensions]: ../registry/struct.Extensions.html #[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 @@ -600,13 +609,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); } } @@ -629,19 +638,18 @@ where fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) { 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); } } @@ -743,7 +751,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()); } @@ -786,7 +798,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 57ce2aff0c..cc86f03c74 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::{ @@ -188,14 +188,14 @@ where fn format_event( &self, ctx: &FmtContext<'_, S, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result where S: Subscriber + 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(); @@ -205,7 +205,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)?; @@ -323,12 +323,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() } @@ -338,38 +334,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(()) } } @@ -489,7 +491,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 db977c348f..91a6f1f934 100644 --- a/tracing-subscriber/src/fmt/format/mod.rs +++ b/tracing-subscriber/src/fmt/format/mod.rs @@ -7,7 +7,7 @@ use crate::{ registry::LookupSpan, }; -use std::fmt::{self, Write}; +use std::fmt::{self, Debug, Display, Write}; use tracing_core::{ field::{self, Field, Visit}, span, Event, Level, Subscriber, @@ -31,9 +31,7 @@ mod pretty; #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))] 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::Subscriber`] or [`fmt::Layer`]. Each time an event is /// dispatched to [`fmt::Subscriber`] or [`fmt::Layer`], the subscriber or layer forwards it to @@ -45,9 +43,13 @@ use fmt::{Debug, Display}; /// # Examples /// /// ```rust -/// use std::fmt::{self, Write}; +/// use std::fmt; /// use tracing_core::{Subscriber, 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; @@ -60,7 +62,7 @@ use fmt::{Debug, Display}; /// fn format_event( /// &self, /// ctx: &FmtContext<'_, S, N>, -/// writer: &mut dyn fmt::Write, +/// mut writer: format::Writer<'_>, /// event: &Event<'_>, /// ) -> fmt::Result { /// // Write level and target @@ -97,7 +99,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) /// } @@ -110,24 +112,25 @@ use fmt::{Debug, Display}; /// DEBUG yak_shaving::shaver: some-span{field-on-span=foo}: started shaving yak /// ``` /// -/// [`fmt::Subscriber`]: ../struct.Subscriber.html -/// [`fmt::Layer`]: ../struct.Layer.html +/// [`fmt::Layer`]: super::Layer +/// [`fmt::Subscriber`]: super::Subscriber +/// [`Event`]: tracing::Event pub trait FormatEvent where S: Subscriber + 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<'_, S, N>, - writer: &mut dyn fmt::Write, + writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result; } impl FormatEvent - for fn(ctx: &FmtContext<'_, S, N>, &mut dyn fmt::Write, &Event<'_>) -> fmt::Result + for fn(ctx: &FmtContext<'_, S, N>, Writer<'_>, &Event<'_>) -> fmt::Result where S: Subscriber + for<'a> LookupSpan<'a>, N: for<'a> FormatFields<'a> + 'static, @@ -135,13 +138,13 @@ where fn format_event( &self, ctx: &FmtContext<'_, S, 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 [`FmtSubscriber`]. Each /// time a span or event with fields is recorded, the subscriber will format @@ -150,23 +153,23 @@ where /// [set of fields]: ../field/trait.RecordFields.html /// [`FmtSubscriber`]: ../fmt/struct.Subscriber.html 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) } } @@ -204,11 +207,29 @@ pub fn json() -> Format { /// [`FormatFields`]: trait.FormatFields.html 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. /// @@ -222,7 +243,7 @@ pub struct FieldFn(F); /// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html 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. @@ -256,6 +277,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 { @@ -441,7 +571,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, { @@ -519,7 +649,7 @@ where fn format_event( &self, ctx: &FmtContext<'_, S, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { #[cfg(feature = "tracing-log")] @@ -529,7 +659,7 @@ where #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - self.format_timestamp(writer)?; + self.format_timestamp(&mut writer)?; if self.display_level { let fmt_level = { @@ -578,7 +708,8 @@ where if self.display_target { write!(writer, "{}: ", meta.target())?; } - ctx.format_fields(writer, event)?; + + ctx.format_fields(writer.by_ref(), event)?; writeln!(writer) } } @@ -592,7 +723,7 @@ where fn format_event( &self, ctx: &FmtContext<'_, S, N>, - writer: &mut dyn fmt::Write, + mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result { #[cfg(feature = "tracing-log")] @@ -602,7 +733,7 @@ where #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - self.format_timestamp(writer)?; + self.format_timestamp(&mut writer)?; if self.display_level { let fmt_level = { @@ -650,7 +781,8 @@ where if self.display_target { write!(writer, "{}:", meta.target())?; } - ctx.format_fields(writer, event)?; + + ctx.format_fields(writer.by_ref(), event)?; let span = event .parent() @@ -679,22 +811,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. /// /// [`FormatFields`]: trait.FormatFields.html @@ -707,11 +835,11 @@ pub struct DefaultFields { /// The [visitor] produced by [`DefaultFields`]'s [`MakeVisitor`] implementation. /// -/// [visitor]: ../../field/trait.Visit.html -/// [`DefaultFields`]: struct.DefaultFields.html -/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html +/// [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, } @@ -731,11 +859,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) } } @@ -749,7 +877,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, @@ -815,17 +943,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 } } @@ -1107,13 +1225,13 @@ impl<'a> fmt::Display for FmtLevel<'a> { // === 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(), @@ -1124,7 +1242,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() { @@ -1135,7 +1253,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 @@ -1144,18 +1262,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() } @@ -1326,12 +1444,12 @@ pub(super) mod test { subscriber::with_default, }; - 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 affc44a1a4..568fea27aa 100644 --- a/tracing-subscriber/src/fmt/format/pretty.rs +++ b/tracing-subscriber/src/fmt/format/pretty.rs @@ -95,7 +95,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")] @@ -104,9 +104,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()) @@ -128,7 +128,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); @@ -222,17 +222,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() } @@ -258,12 +263,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 d761f40034..d86ffdc0ff 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);