Skip to content

Commit bcd0972

Browse files
authored
subscriber: Add SubscriberBuilder/Layer accessors (#1871)
## Motivation `SubscriberBuilder`s and `Layer`s configured with custom event/field formatters do not provide any means of accessing or mutating those formatters. Any configuration that needs to be done must be done before setting them on the builder/layer. This is frustrating as it makes it difficult to provide a pre-configured API akin to `tracing_subscriber::fmt()` along with accessors like `.compact()` that modify the formatter. ## Solution Add accessors `.map_event_format()` and `.map_fmt_fields()` to `SubscriberBuilder` and `Layer` that map the existing formatter through a closure. This allows the closure to modify it or to derive a new formatter from it with a different type. Also add a `.map_writer()` method that does the same thing for the `MakeWriter`, to round out the accessors for the various type parameters. The filter type is currently restricted to just `LevelFilter` or `EnvFilter` and so this does not add a corresponding `.map_filter()`. That can be added later if we add the ability to attach arbitrary filters. Also fix some minor docs issues that were spotted as part of implementing this. Fixes #1756
1 parent 24ee184 commit bcd0972

File tree

3 files changed

+196
-15
lines changed

3 files changed

+196
-15
lines changed

tracing-subscriber/src/fmt/fmt_layer.rs

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ where
8787
N: for<'writer> FormatFields<'writer> + 'static,
8888
W: for<'writer> MakeWriter<'writer> + 'static,
8989
{
90-
/// Sets the [event formatter][`FormatEvent`] that the layer will use to
91-
/// format events.
90+
/// Sets the [event formatter][`FormatEvent`] that the layer being built will
91+
/// use to format events.
9292
///
9393
/// The event formatter may be any type implementing the [`FormatEvent`]
9494
/// trait, which is implemented for all functions taking a [`FmtContext`], a
@@ -122,11 +122,40 @@ where
122122
_inner: self._inner,
123123
}
124124
}
125+
126+
/// Updates the event formatter by applying a function to the existing event formatter.
127+
///
128+
/// This sets the event formatter that the layer being built will use to record fields.
129+
///
130+
/// # Examples
131+
///
132+
/// Updating an event formatter:
133+
///
134+
/// ```rust
135+
/// let layer = tracing_subscriber::fmt::layer()
136+
/// .map_event_format(|e| e.compact());
137+
/// # // this is necessary for type inference.
138+
/// # use tracing_subscriber::Layer as _;
139+
/// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default());
140+
/// ```
141+
pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> Layer<S, N, E2, W>
142+
where
143+
E2: FormatEvent<S, N> + 'static,
144+
{
145+
Layer {
146+
fmt_fields: self.fmt_fields,
147+
fmt_event: f(self.fmt_event),
148+
fmt_span: self.fmt_span,
149+
make_writer: self.make_writer,
150+
is_ansi: self.is_ansi,
151+
_inner: self._inner,
152+
}
153+
}
125154
}
126155

127156
// This needs to be a seperate impl block because they place different bounds on the type parameters.
128157
impl<S, N, E, W> Layer<S, N, E, W> {
129-
/// Sets the [`MakeWriter`] that the [`Layer`] being built will use to write events.
158+
/// Sets the [`MakeWriter`] that the layer being built will use to write events.
130159
///
131160
/// # Examples
132161
///
@@ -142,9 +171,6 @@ impl<S, N, E, W> Layer<S, N, E, W> {
142171
/// # use tracing_subscriber::Layer as _;
143172
/// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default());
144173
/// ```
145-
///
146-
/// [`MakeWriter`]: ../fmt/trait.MakeWriter.html
147-
/// [`Layer`]: ../layer/trait.Layer.html
148174
pub fn with_writer<W2>(self, make_writer: W2) -> Layer<S, N, E, W2>
149175
where
150176
W2: for<'writer> MakeWriter<'writer> + 'static,
@@ -201,6 +227,39 @@ impl<S, N, E, W> Layer<S, N, E, W> {
201227
..self
202228
}
203229
}
230+
231+
/// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
232+
///
233+
/// This sets the [`MakeWriter`] that the layer being built will use to write events.
234+
///
235+
/// # Examples
236+
///
237+
/// Redirect output to stderr if level is <= WARN:
238+
///
239+
/// ```rust
240+
/// use tracing::Level;
241+
/// use tracing_subscriber::fmt::{self, writer::MakeWriterExt};
242+
///
243+
/// let stderr = std::io::stderr.with_max_level(Level::WARN);
244+
/// let layer = fmt::layer()
245+
/// .map_writer(move |w| stderr.or_else(w));
246+
/// # // this is necessary for type inference.
247+
/// # use tracing_subscriber::Layer as _;
248+
/// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default());
249+
/// ```
250+
pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Layer<S, N, E, W2>
251+
where
252+
W2: for<'writer> MakeWriter<'writer> + 'static,
253+
{
254+
Layer {
255+
fmt_fields: self.fmt_fields,
256+
fmt_event: self.fmt_event,
257+
fmt_span: self.fmt_span,
258+
is_ansi: self.is_ansi,
259+
make_writer: f(self.make_writer),
260+
_inner: self._inner,
261+
}
262+
}
204263
}
205264

206265
impl<S, N, L, T, W> Layer<S, N, format::Format<L, T>, W>
@@ -481,6 +540,36 @@ impl<S, N, E, W> Layer<S, N, E, W> {
481540
_inner: self._inner,
482541
}
483542
}
543+
544+
/// Updates the field formatter by applying a function to the existing field formatter.
545+
///
546+
/// This sets the field formatter that the layer being built will use to record fields.
547+
///
548+
/// # Examples
549+
///
550+
/// Updating a field formatter:
551+
///
552+
/// ```rust
553+
/// use tracing_subscriber::field::MakeExt;
554+
/// let layer = tracing_subscriber::fmt::layer()
555+
/// .map_fmt_fields(|f| f.debug_alt());
556+
/// # // this is necessary for type inference.
557+
/// # use tracing_subscriber::Layer as _;
558+
/// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default());
559+
/// ```
560+
pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> Layer<S, N2, E, W>
561+
where
562+
N2: for<'writer> FormatFields<'writer> + 'static,
563+
{
564+
Layer {
565+
fmt_event: self.fmt_event,
566+
fmt_fields: f(self.fmt_fields),
567+
fmt_span: self.fmt_span,
568+
make_writer: self.make_writer,
569+
is_ansi: self.is_ansi,
570+
_inner: self._inner,
571+
}
572+
}
484573
}
485574

486575
impl<S> Default for Layer<S> {

tracing-subscriber/src/fmt/mod.rs

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ where
923923
}
924924

925925
impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
926-
/// Sets the Visitor that the subscriber being built will use to record
926+
/// Sets the field formatter that the subscriber being built will use to record
927927
/// fields.
928928
///
929929
/// For example:
@@ -1021,7 +1021,7 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
10211021
/// subscriber.
10221022
///
10231023
/// If the max level has already been set, or a [`EnvFilter`] was added by
1024-
/// [`with_filter`], this replaces that configuration with the new
1024+
/// [`with_env_filter`], this replaces that configuration with the new
10251025
/// maximum level.
10261026
///
10271027
/// # Examples
@@ -1044,8 +1044,8 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
10441044
/// .finish();
10451045
/// ```
10461046
/// [verbosity level]: https://docs.rs/tracing-core/0.1.5/tracing_core/struct.Level.html
1047-
/// [`EnvFilter`]: ../filter/struct.EnvFilter.html
1048-
/// [`with_filter`]: #method.with_filter
1047+
/// [`EnvFilter`]: struct@crate::filter::EnvFilter
1048+
/// [`with_env_filter`]: fn@Self::with_env_filter
10491049
pub fn with_max_level(
10501050
self,
10511051
filter: impl Into<LevelFilter>,
@@ -1057,8 +1057,26 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
10571057
}
10581058
}
10591059

1060-
/// Sets the function that the subscriber being built should use to format
1061-
/// events that occur.
1060+
/// Sets the [event formatter][`FormatEvent`] that the subscriber being built
1061+
/// will use to format events that occur.
1062+
///
1063+
/// The event formatter may be any type implementing the [`FormatEvent`]
1064+
/// trait, which is implemented for all functions taking a [`FmtContext`], a
1065+
/// [`Writer`], and an [`Event`].
1066+
///
1067+
/// # Examples
1068+
///
1069+
/// Setting a type implementing [`FormatEvent`] as the formatter:
1070+
///
1071+
/// ```rust
1072+
/// use tracing_subscriber::fmt::format;
1073+
///
1074+
/// let subscriber = tracing_subscriber::fmt()
1075+
/// .event_format(format().compact())
1076+
/// .finish();
1077+
/// ```
1078+
///
1079+
/// [`Writer`]: struct@self::format::Writer
10621080
pub fn event_format<E2>(self, fmt_event: E2) -> SubscriberBuilder<N, E2, F, W>
10631081
where
10641082
E2: FormatEvent<Registry, N> + 'static,
@@ -1085,8 +1103,6 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
10851103
/// .with_writer(io::stderr)
10861104
/// .init();
10871105
/// ```
1088-
///
1089-
/// [`MakeWriter`]: trait.MakeWriter.html
10901106
pub fn with_writer<W2>(self, make_writer: W2) -> SubscriberBuilder<N, E, F, W2>
10911107
where
10921108
W2: for<'writer> MakeWriter<'writer> + 'static,
@@ -1127,6 +1143,82 @@ impl<N, E, F, W> SubscriberBuilder<N, E, F, W> {
11271143
inner: self.inner.with_writer(TestWriter::default()),
11281144
}
11291145
}
1146+
1147+
/// Updates the event formatter by applying a function to the existing event formatter.
1148+
///
1149+
/// This sets the event formatter that the subscriber being built will use to record fields.
1150+
///
1151+
/// # Examples
1152+
///
1153+
/// Updating an event formatter:
1154+
///
1155+
/// ```rust
1156+
/// let subscriber = tracing_subscriber::fmt()
1157+
/// .map_event_format(|e| e.compact())
1158+
/// .finish();
1159+
/// ```
1160+
pub fn map_event_format<E2>(self, f: impl FnOnce(E) -> E2) -> SubscriberBuilder<N, E2, F, W>
1161+
where
1162+
E2: FormatEvent<Registry, N> + 'static,
1163+
N: for<'writer> FormatFields<'writer> + 'static,
1164+
W: for<'writer> MakeWriter<'writer> + 'static,
1165+
{
1166+
SubscriberBuilder {
1167+
filter: self.filter,
1168+
inner: self.inner.map_event_format(f),
1169+
}
1170+
}
1171+
1172+
/// Updates the field formatter by applying a function to the existing field formatter.
1173+
///
1174+
/// This sets the field formatter that the subscriber being built will use to record fields.
1175+
///
1176+
/// # Examples
1177+
///
1178+
/// Updating a field formatter:
1179+
///
1180+
/// ```rust
1181+
/// use tracing_subscriber::field::MakeExt;
1182+
/// let subscriber = tracing_subscriber::fmt()
1183+
/// .map_fmt_fields(|f| f.debug_alt())
1184+
/// .finish();
1185+
/// ```
1186+
pub fn map_fmt_fields<N2>(self, f: impl FnOnce(N) -> N2) -> SubscriberBuilder<N2, E, F, W>
1187+
where
1188+
N2: for<'writer> FormatFields<'writer> + 'static,
1189+
{
1190+
SubscriberBuilder {
1191+
filter: self.filter,
1192+
inner: self.inner.map_fmt_fields(f),
1193+
}
1194+
}
1195+
1196+
/// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
1197+
///
1198+
/// This sets the [`MakeWriter`] that the subscriber being built will use to write events.
1199+
///
1200+
/// # Examples
1201+
///
1202+
/// Redirect output to stderr if level is <= WARN:
1203+
///
1204+
/// ```rust
1205+
/// use tracing::Level;
1206+
/// use tracing_subscriber::fmt::{self, writer::MakeWriterExt};
1207+
///
1208+
/// let stderr = std::io::stderr.with_max_level(Level::WARN);
1209+
/// let layer = tracing_subscriber::fmt()
1210+
/// .map_writer(move |w| stderr.or_else(w))
1211+
/// .finish();
1212+
/// ```
1213+
pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> SubscriberBuilder<N, E, F, W2>
1214+
where
1215+
W2: for<'writer> MakeWriter<'writer> + 'static,
1216+
{
1217+
SubscriberBuilder {
1218+
filter: self.filter,
1219+
inner: self.inner.map_writer(f),
1220+
}
1221+
}
11301222
}
11311223

11321224
/// Install a global tracing subscriber that listens for events and

tracing-subscriber/src/layer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ where
857857
/// per-layer filtering.
858858
///
859859
/// [`Filtered`]: crate::filter::Filtered
860-
/// [plf]: #per-layer-filtering
860+
/// [plf]: crate::layer#per-layer-filtering
861861
#[cfg(all(feature = "registry", feature = "std"))]
862862
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
863863
fn with_filter<F>(self, filter: F) -> filter::Filtered<Self, F, S>

0 commit comments

Comments
 (0)