1 //! Utilities for working with [fields] and [field visitors].
2 //!
3 //! [fields]: tracing_core::field
4 //! [field visitors]: tracing_core::field::Visit
5 use core::{fmt, marker::PhantomData};
6 pub use tracing_core::field::Visit;
7 use tracing_core::{
8     span::{Attributes, Record},
9     Event,
10 };
11 pub mod debug;
12 pub mod delimited;
13 pub mod display;
14 
15 /// Creates new [visitors].
16 ///
17 /// A type implementing `MakeVisitor` represents a composable factory for types
18 /// implementing the [`Visit` trait][visitors]. The `MakeVisitor` trait defines
19 /// a single function, `make_visitor`, which takes in a `T`-typed `target` and
20 /// returns a type implementing `Visit` configured for that target. A target may
21 /// be a string, output stream, or data structure that the visitor will record
22 /// data to, configuration variables that determine the visitor's behavior, or
23 /// `()` when no input is required to produce a visitor.
24 ///
25 /// [visitors]: tracing_core::field::Visit
26 pub trait MakeVisitor<T> {
27     /// The visitor type produced by this `MakeVisitor`.
28     type Visitor: Visit;
29 
30     /// Make a new visitor for the provided `target`.
make_visitor(&self, target: T) -> Self::Visitor31     fn make_visitor(&self, target: T) -> Self::Visitor;
32 }
33 
34 /// A [visitor] that produces output once it has visited a set of fields.
35 ///
36 /// [visitor]: tracing_core::field::Visit
37 pub trait VisitOutput<Out>: Visit {
38     /// Completes the visitor, returning any output.
39     ///
40     /// This is called once a full set of fields has been visited.
finish(self) -> Out41     fn finish(self) -> Out;
42 
43     /// Visit a set of fields, and return the output of finishing the visitor
44     /// once the fields have been visited.
visit<R>(mut self, fields: &R) -> Out where R: RecordFields, Self: Sized,45     fn visit<R>(mut self, fields: &R) -> Out
46     where
47         R: RecordFields,
48         Self: Sized,
49     {
50         fields.record(&mut self);
51         self.finish()
52     }
53 }
54 
55 /// Extension trait implemented by types which can be recorded by a [visitor].
56 ///
57 /// This allows writing code that is generic over `tracing_core`'s
58 /// [`span::Attributes`][attr], [`span::Record`][rec], and [`Event`]
59 /// types. These types all provide inherent `record` methods that allow a
60 /// visitor to record their fields, but there is no common trait representing this.
61 ///
62 /// With `RecordFields`, we can write code like this:
63 /// ```
64 /// use tracing_core::field::Visit;
65 /// # use tracing_core::field::Field;
66 /// use tracing_subscriber::field::RecordFields;
67 ///
68 /// struct MyVisitor {
69 ///     // ...
70 /// }
71 /// # impl MyVisitor { fn new() -> Self { Self{} } }
72 /// impl Visit for MyVisitor {
73 ///     // ...
74 /// # fn record_debug(&mut self, _: &Field, _: &dyn std::fmt::Debug) {}
75 /// }
76 ///
77 /// fn record_with_my_visitor<R>(r: R)
78 /// where
79 ///     R: RecordFields,
80 /// {
81 ///     let mut visitor = MyVisitor::new();
82 ///     r.record(&mut visitor);
83 /// }
84 /// ```
85 /// [visitor]: tracing_core::field::Visit
86 /// [attr]: tracing_core::span::Attributes
87 /// [rec]: tracing_core::span::Record
88 pub trait RecordFields: crate::sealed::Sealed<RecordFieldsMarker> {
89     /// Record all the fields in `self` with the provided `visitor`.
record(&self, visitor: &mut dyn Visit)90     fn record(&self, visitor: &mut dyn Visit);
91 }
92 
93 /// Extension trait implemented for all `MakeVisitor` implementations that
94 /// produce a visitor implementing `VisitOutput`.
95 pub trait MakeOutput<T, Out>
96 where
97     Self: MakeVisitor<T> + crate::sealed::Sealed<(T, Out)>,
98     Self::Visitor: VisitOutput<Out>,
99 {
100     /// Visits all fields in `fields` with a new visitor constructed from
101     /// `target`.
visit_with<F>(&self, target: T, fields: &F) -> Out where F: RecordFields,102     fn visit_with<F>(&self, target: T, fields: &F) -> Out
103     where
104         F: RecordFields,
105     {
106         self.make_visitor(target).visit(fields)
107     }
108 }
109 
110 feature! {
111     #![feature = "std"]
112     use std::io;
113 
114     /// Extension trait implemented by visitors to indicate that they write to an
115     /// `io::Write` instance, and allow access to that writer.
116     pub trait VisitWrite: VisitOutput<Result<(), io::Error>> {
117         /// Returns the writer that this visitor writes to.
118         fn writer(&mut self) -> &mut dyn io::Write;
119     }
120 }
121 
122 /// Extension trait implemented by visitors to indicate that they write to a
123 /// `fmt::Write` instance, and allow access to that writer.
124 pub trait VisitFmt: VisitOutput<fmt::Result> {
125     /// Returns the formatter that this visitor writes to.
writer(&mut self) -> &mut dyn fmt::Write126     fn writer(&mut self) -> &mut dyn fmt::Write;
127 }
128 
129 /// Extension trait providing `MakeVisitor` combinators.
130 pub trait MakeExt<T>
131 where
132     Self: MakeVisitor<T> + Sized,
133     Self: crate::sealed::Sealed<MakeExtMarker<T>>,
134 {
135     /// Wraps `self` so that any `fmt::Debug` fields are recorded using the
136     /// alternate formatter (`{:#?}`).
debug_alt(self) -> debug::Alt<Self>137     fn debug_alt(self) -> debug::Alt<Self> {
138         debug::Alt::new(self)
139     }
140 
141     /// Wraps `self` so that any string fields named "message" are recorded
142     /// using `fmt::Display`.
display_messages(self) -> display::Messages<Self>143     fn display_messages(self) -> display::Messages<Self> {
144         display::Messages::new(self)
145     }
146 
147     /// Wraps `self` so that when fields are formatted to a writer, they are
148     /// separated by the provided `delimiter`.
delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self> where D: AsRef<str> + Clone, Self::Visitor: VisitFmt,149     fn delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self>
150     where
151         D: AsRef<str> + Clone,
152         Self::Visitor: VisitFmt,
153     {
154         delimited::Delimited::new(delimiter, self)
155     }
156 }
157 
158 // === impl RecordFields ===
159 
160 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {}
161 impl<'a> RecordFields for Event<'a> {
record(&self, visitor: &mut dyn Visit)162     fn record(&self, visitor: &mut dyn Visit) {
163         Event::record(self, visitor)
164     }
165 }
166 
167 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Attributes<'a> {}
168 impl<'a> RecordFields for Attributes<'a> {
record(&self, visitor: &mut dyn Visit)169     fn record(&self, visitor: &mut dyn Visit) {
170         Attributes::record(self, visitor)
171     }
172 }
173 
174 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Record<'a> {}
175 impl<'a> RecordFields for Record<'a> {
record(&self, visitor: &mut dyn Visit)176     fn record(&self, visitor: &mut dyn Visit) {
177         Record::record(self, visitor)
178     }
179 }
180 
181 impl<'a, F> crate::sealed::Sealed<RecordFieldsMarker> for &'a F where F: RecordFields {}
182 impl<'a, F> RecordFields for &'a F
183 where
184     F: RecordFields,
185 {
record(&self, visitor: &mut dyn Visit)186     fn record(&self, visitor: &mut dyn Visit) {
187         F::record(*self, visitor)
188     }
189 }
190 
191 // === blanket impls ===
192 
193 impl<T, V, F> MakeVisitor<T> for F
194 where
195     F: Fn(T) -> V,
196     V: Visit,
197 {
198     type Visitor = V;
make_visitor(&self, target: T) -> Self::Visitor199     fn make_visitor(&self, target: T) -> Self::Visitor {
200         (self)(target)
201     }
202 }
203 
204 impl<T, Out, M> crate::sealed::Sealed<(T, Out)> for M
205 where
206     M: MakeVisitor<T>,
207     M::Visitor: VisitOutput<Out>,
208 {
209 }
210 
211 impl<T, Out, M> MakeOutput<T, Out> for M
212 where
213     M: MakeVisitor<T>,
214     M::Visitor: VisitOutput<Out>,
215 {
216 }
217 
218 impl<T, M> crate::sealed::Sealed<MakeExtMarker<T>> for M where M: MakeVisitor<T> + Sized {}
219 
220 impl<T, M> MakeExt<T> for M
221 where
222     M: MakeVisitor<T> + Sized,
223     M: crate::sealed::Sealed<MakeExtMarker<T>>,
224 {
225 }
226 
227 #[derive(Debug)]
228 #[doc(hidden)]
229 pub struct MakeExtMarker<T> {
230     _p: PhantomData<T>,
231 }
232 
233 #[derive(Debug)]
234 #[doc(hidden)]
235 pub struct RecordFieldsMarker {
236     _p: (),
237 }
238 
239 #[cfg(all(test, feature = "alloc"))]
240 #[macro_use]
241 pub(in crate::field) mod test_util {
242     use super::*;
243     pub(in crate::field) use alloc::string::String;
244     use tracing_core::{
245         callsite::Callsite,
246         field::{Field, Value},
247         metadata::{Kind, Level, Metadata},
248     };
249 
250     pub(crate) struct TestAttrs1;
251     pub(crate) struct TestAttrs2;
252 
253     impl TestAttrs1 {
with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T254         pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
255             let fieldset = TEST_META_1.fields();
256             let values = &[
257                 (
258                     &fieldset.field("question").unwrap(),
259                     Some(&"life, the universe, and everything" as &dyn Value),
260                 ),
261                 (&fieldset.field("question.answer").unwrap(), None),
262                 (
263                     &fieldset.field("tricky").unwrap(),
264                     Some(&true as &dyn Value),
265                 ),
266                 (
267                     &fieldset.field("can_you_do_it").unwrap(),
268                     Some(&true as &dyn Value),
269                 ),
270             ];
271             let valueset = fieldset.value_set(values);
272             let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
273             f(attrs)
274         }
275     }
276 
277     impl TestAttrs2 {
with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T278         pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
279             let fieldset = TEST_META_1.fields();
280             let none = tracing_core::field::debug(&Option::<&str>::None);
281             let values = &[
282                 (
283                     &fieldset.field("question").unwrap(),
284                     Some(&none as &dyn Value),
285                 ),
286                 (
287                     &fieldset.field("question.answer").unwrap(),
288                     Some(&42 as &dyn Value),
289                 ),
290                 (
291                     &fieldset.field("tricky").unwrap(),
292                     Some(&true as &dyn Value),
293                 ),
294                 (
295                     &fieldset.field("can_you_do_it").unwrap(),
296                     Some(&false as &dyn Value),
297                 ),
298             ];
299             let valueset = fieldset.value_set(values);
300             let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
301             f(attrs)
302         }
303     }
304 
305     struct TestCallsite1;
306     static TEST_CALLSITE_1: &'static dyn Callsite = &TestCallsite1;
307     static TEST_META_1: Metadata<'static> = tracing_core::metadata! {
308         name: "field_test1",
309         target: module_path!(),
310         level: Level::INFO,
311         fields: &["question", "question.answer", "tricky", "can_you_do_it"],
312         callsite: TEST_CALLSITE_1,
313         kind: Kind::SPAN,
314     };
315 
316     impl Callsite for TestCallsite1 {
set_interest(&self, _: tracing_core::subscriber::Interest)317         fn set_interest(&self, _: tracing_core::subscriber::Interest) {
318             unimplemented!()
319         }
320 
metadata(&self) -> &Metadata<'_>321         fn metadata(&self) -> &Metadata<'_> {
322             &TEST_META_1
323         }
324     }
325 
326     pub(crate) struct MakeDebug;
327     pub(crate) struct DebugVisitor<'a> {
328         writer: &'a mut dyn fmt::Write,
329         err: fmt::Result,
330     }
331 
332     impl<'a> DebugVisitor<'a> {
new(writer: &'a mut dyn fmt::Write) -> Self333         pub(crate) fn new(writer: &'a mut dyn fmt::Write) -> Self {
334             Self {
335                 writer,
336                 err: Ok(()),
337             }
338         }
339     }
340 
341     impl<'a> Visit for DebugVisitor<'a> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)342         fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
343             write!(self.writer, "{}={:?}", field, value).unwrap();
344         }
345     }
346 
347     impl<'a> VisitOutput<fmt::Result> for DebugVisitor<'a> {
finish(self) -> fmt::Result348         fn finish(self) -> fmt::Result {
349             self.err
350         }
351     }
352 
353     impl<'a> VisitFmt for DebugVisitor<'a> {
writer(&mut self) -> &mut dyn fmt::Write354         fn writer(&mut self) -> &mut dyn fmt::Write {
355             self.writer
356         }
357     }
358 
359     impl<'a> MakeVisitor<&'a mut dyn fmt::Write> for MakeDebug {
360         type Visitor = DebugVisitor<'a>;
make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a>361         fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> {
362             DebugVisitor::new(w)
363         }
364     }
365 }
366