Skip to content

Commit f6bf927

Browse files
committed
subscriber: replace dyn Write with a Writer type (#1661)
## Motivation Currently, the `FormatEvent` and `FormatFields` traits in `tracing-subscriber` are passed a `&mut dyn fmt::Write` trait object to write formatted representations of events and fields to. This is fine, but it doesn't give us the ability to easily provide additional configuration to the formatter, such as whether ANSI color codes are supported. Issue #1651 describes some approaches for adding a way to expose the ANSI color code configuration to custom formatters. In particular, the proposed solution involves wrapping the `fmt::Write` trait object in an opaque struct, which can then implement additional methods for exposing information like "are ANSI colors enabled" to the formatter. Since this changes the signature of the `FormatEvent::format_event` and `FormatFields::format_fields` methods, it's a breaking change. Therefore, we need to make this change _now_ if we want to get the API change in for `tracing-subscriber` 0.3. ## Solution This branch adds a `Writer` struct that wraps the `&mut dyn fmt::Write` trait object, and changes the various method signatures as appropriate. It does **not** actually implement the change related to ANSI color formatting. Once we change these methods' signatures to accept a `Writer` struct, we can add as many methods to that struct as we like without making additional breaking API changes. Therefore, this branch _just_ makes the breaking change that's necessary to get in before v0.3 is released. Propagating the ANSI color configuration can be implemented in a future branch. Signed-off-by: Eliza Weisman <eliza@buoyant.io>
1 parent 89ba577 commit f6bf927

File tree

7 files changed

+299
-162
lines changed

7 files changed

+299
-162
lines changed

tracing-error/src/layer.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ where
4545
if span.extensions().get::<FormattedFields<F>>().is_some() {
4646
return;
4747
}
48-
let mut fields = String::new();
49-
if self.format.format_fields(&mut fields, attrs).is_ok() {
50-
span.extensions_mut()
51-
.insert(FormattedFields::<F>::new(fields));
48+
let mut fields = FormattedFields::<F>::new(String::new());
49+
if self.format.format_fields(fields.as_writer(), attrs).is_ok() {
50+
span.extensions_mut().insert(fields);
5251
}
5352
}
5453

tracing-subscriber/src/fmt/fmt_layer.rs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -533,37 +533,46 @@ where
533533
///
534534
/// [extensions]: ../registry/struct.Extensions.html
535535
#[derive(Default)]
536-
pub struct FormattedFields<E> {
537-
_format_event: PhantomData<fn(E)>,
536+
pub struct FormattedFields<E: ?Sized> {
537+
_format_fields: PhantomData<fn(E)>,
538538
/// The formatted fields of a span.
539539
pub fields: String,
540540
}
541541

542-
impl<E> FormattedFields<E> {
542+
impl<E: ?Sized> FormattedFields<E> {
543543
/// Returns a new `FormattedFields`.
544544
pub fn new(fields: String) -> Self {
545545
Self {
546546
fields,
547-
_format_event: PhantomData,
547+
_format_fields: PhantomData,
548548
}
549549
}
550+
551+
/// Returns a new [`format::Writer`] for writing to this `FormattedFields`.
552+
///
553+
/// The returned [`format::Writer`] can be used with the
554+
/// [`FormatFields::format_fields`] method.
555+
pub fn as_writer(&mut self) -> format::Writer<'_> {
556+
format::Writer::new(&mut self.fields)
557+
}
550558
}
551559

552-
impl<E> fmt::Debug for FormattedFields<E> {
560+
impl<E: ?Sized> fmt::Debug for FormattedFields<E> {
553561
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
554562
f.debug_struct("FormattedFields")
555563
.field("fields", &self.fields)
564+
.field("formatter", &format_args!("{}", std::any::type_name::<E>()))
556565
.finish()
557566
}
558567
}
559568

560-
impl<E> fmt::Display for FormattedFields<E> {
569+
impl<E: ?Sized> fmt::Display for FormattedFields<E> {
561570
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562-
write!(f, "{}", self.fields)
571+
fmt::Display::fmt(&self.fields, f)
563572
}
564573
}
565574

566-
impl<E> Deref for FormattedFields<E> {
575+
impl<E: ?Sized> Deref for FormattedFields<E> {
567576
type Target = String;
568577
fn deref(&self) -> &Self::Target {
569578
&self.fields
@@ -600,13 +609,13 @@ where
600609
let mut extensions = span.extensions_mut();
601610

602611
if extensions.get_mut::<FormattedFields<N>>().is_none() {
603-
let mut buf = String::new();
604-
if self.fmt_fields.format_fields(&mut buf, attrs).is_ok() {
605-
let fmt_fields = FormattedFields {
606-
fields: buf,
607-
_format_event: PhantomData::<fn(N)>,
608-
};
609-
extensions.insert(fmt_fields);
612+
let mut fields = FormattedFields::<N>::new(String::new());
613+
if self
614+
.fmt_fields
615+
.format_fields(fields.as_writer(), attrs)
616+
.is_ok()
617+
{
618+
extensions.insert(fields);
610619
}
611620
}
612621

@@ -629,19 +638,18 @@ where
629638
fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
630639
let span = ctx.span(id).expect("Span not found, this is a bug");
631640
let mut extensions = span.extensions_mut();
632-
if let Some(FormattedFields { ref mut fields, .. }) =
633-
extensions.get_mut::<FormattedFields<N>>()
634-
{
641+
if let Some(fields) = extensions.get_mut::<FormattedFields<N>>() {
635642
let _ = self.fmt_fields.add_fields(fields, values);
636-
} else {
637-
let mut buf = String::new();
638-
if self.fmt_fields.format_fields(&mut buf, values).is_ok() {
639-
let fmt_fields = FormattedFields {
640-
fields: buf,
641-
_format_event: PhantomData::<fn(N)>,
642-
};
643-
extensions.insert(fmt_fields);
644-
}
643+
return;
644+
}
645+
646+
let mut fields = FormattedFields::<N>::new(String::new());
647+
if self
648+
.fmt_fields
649+
.format_fields(fields.as_writer(), values)
650+
.is_ok()
651+
{
652+
extensions.insert(fields);
645653
}
646654
}
647655

@@ -743,7 +751,11 @@ where
743751
};
744752

745753
let ctx = self.make_ctx(ctx);
746-
if self.fmt_event.format_event(&ctx, &mut buf, event).is_ok() {
754+
if self
755+
.fmt_event
756+
.format_event(&ctx, format::Writer::new(&mut buf), event)
757+
.is_ok()
758+
{
747759
let mut writer = self.make_writer.make_writer_for(event.metadata());
748760
let _ = io::Write::write_all(&mut writer, buf.as_bytes());
749761
}
@@ -786,7 +798,7 @@ where
786798
{
787799
fn format_fields<R: RecordFields>(
788800
&self,
789-
writer: &'writer mut dyn fmt::Write,
801+
writer: format::Writer<'writer>,
790802
fields: R,
791803
) -> fmt::Result {
792804
self.fmt_fields.format_fields(writer, fields)

tracing-subscriber/src/fmt/format/json.rs

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Format, FormatEvent, FormatFields, FormatTime};
1+
use super::{Format, FormatEvent, FormatFields, FormatTime, Writer};
22
use crate::{
33
field::{RecordFields, VisitOutput},
44
fmt::{
@@ -188,14 +188,14 @@ where
188188
fn format_event(
189189
&self,
190190
ctx: &FmtContext<'_, S, N>,
191-
writer: &mut dyn fmt::Write,
191+
mut writer: Writer<'_>,
192192
event: &Event<'_>,
193193
) -> fmt::Result
194194
where
195195
S: Subscriber + for<'a> LookupSpan<'a>,
196196
{
197197
let mut timestamp = String::new();
198-
self.timer.format_time(&mut timestamp)?;
198+
self.timer.format_time(&mut Writer::new(&mut timestamp))?;
199199

200200
#[cfg(feature = "tracing-log")]
201201
let normalized_meta = event.normalized_metadata();
@@ -205,7 +205,7 @@ where
205205
let meta = event.metadata();
206206

207207
let mut visit = || {
208-
let mut serializer = Serializer::new(WriteAdaptor::new(writer));
208+
let mut serializer = Serializer::new(WriteAdaptor::new(&mut writer));
209209

210210
let mut serializer = serializer.serialize_map(None)?;
211211

@@ -323,12 +323,8 @@ impl Default for JsonFields {
323323

324324
impl<'a> FormatFields<'a> for JsonFields {
325325
/// Format the provided `fields` to the provided `writer`, returning a result.
326-
fn format_fields<R: RecordFields>(
327-
&self,
328-
writer: &'a mut dyn fmt::Write,
329-
fields: R,
330-
) -> fmt::Result {
331-
let mut v = JsonVisitor::new(writer);
326+
fn format_fields<R: RecordFields>(&self, mut writer: Writer<'_>, fields: R) -> fmt::Result {
327+
let mut v = JsonVisitor::new(&mut writer);
332328
fields.record(&mut v);
333329
v.finish()
334330
}
@@ -338,38 +334,44 @@ impl<'a> FormatFields<'a> for JsonFields {
338334
/// By default, this appends a space to the current set of fields if it is
339335
/// non-empty, and then calls `self.format_fields`. If different behavior is
340336
/// required, the default implementation of this method can be overridden.
341-
fn add_fields(&self, current: &'a mut String, fields: &Record<'_>) -> fmt::Result {
342-
if !current.is_empty() {
343-
// If fields were previously recorded on this span, we need to parse
344-
// the current set of fields as JSON, add the new fields, and
345-
// re-serialize them. Otherwise, if we just appended the new fields
346-
// to a previously serialized JSON object, we would end up with
347-
// malformed JSON.
348-
//
349-
// XXX(eliza): this is far from efficient, but unfortunately, it is
350-
// necessary as long as the JSON formatter is implemented on top of
351-
// an interface that stores all formatted fields as strings.
352-
//
353-
// We should consider reimplementing the JSON formatter as a
354-
// separate layer, rather than a formatter for the `fmt` layer —
355-
// then, we could store fields as JSON values, and add to them
356-
// without having to parse and re-serialize.
357-
let mut new = String::new();
358-
let map: BTreeMap<&'_ str, serde_json::Value> =
359-
serde_json::from_str(current).map_err(|_| fmt::Error)?;
360-
let mut v = JsonVisitor::new(&mut new);
361-
v.values = map;
362-
fields.record(&mut v);
363-
v.finish()?;
364-
*current = new;
365-
} else {
337+
fn add_fields(
338+
&self,
339+
current: &'a mut FormattedFields<Self>,
340+
fields: &Record<'_>,
341+
) -> fmt::Result {
342+
if current.is_empty() {
366343
// If there are no previously recorded fields, we can just reuse the
367344
// existing string.
368-
let mut v = JsonVisitor::new(current);
345+
let mut writer = current.as_writer();
346+
let mut v = JsonVisitor::new(&mut writer);
369347
fields.record(&mut v);
370348
v.finish()?;
349+
return Ok(());
371350
}
372351

352+
// If fields were previously recorded on this span, we need to parse
353+
// the current set of fields as JSON, add the new fields, and
354+
// re-serialize them. Otherwise, if we just appended the new fields
355+
// to a previously serialized JSON object, we would end up with
356+
// malformed JSON.
357+
//
358+
// XXX(eliza): this is far from efficient, but unfortunately, it is
359+
// necessary as long as the JSON formatter is implemented on top of
360+
// an interface that stores all formatted fields as strings.
361+
//
362+
// We should consider reimplementing the JSON formatter as a
363+
// separate layer, rather than a formatter for the `fmt` layer —
364+
// then, we could store fields as JSON values, and add to them
365+
// without having to parse and re-serialize.
366+
let mut new = String::new();
367+
let map: BTreeMap<&'_ str, serde_json::Value> =
368+
serde_json::from_str(current).map_err(|_| fmt::Error)?;
369+
let mut v = JsonVisitor::new(&mut new);
370+
v.values = map;
371+
fields.record(&mut v);
372+
v.finish()?;
373+
current.fields = new;
374+
373375
Ok(())
374376
}
375377
}
@@ -489,7 +491,7 @@ mod test {
489491

490492
struct MockTime;
491493
impl FormatTime for MockTime {
492-
fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result {
494+
fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
493495
write!(w, "fake time")
494496
}
495497
}

0 commit comments

Comments
 (0)