• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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`][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 /// [event]: tracing_core::event::Event
89 pub trait RecordFields: crate::sealed::Sealed<RecordFieldsMarker> {
90     /// Record all the fields in `self` with the provided `visitor`.
record(&self, visitor: &mut dyn Visit)91     fn record(&self, visitor: &mut dyn Visit);
92 }
93 
94 /// Extension trait implemented for all `MakeVisitor` implementations that
95 /// produce a visitor implementing `VisitOutput`.
96 pub trait MakeOutput<T, Out>
97 where
98     Self: MakeVisitor<T> + crate::sealed::Sealed<(T, Out)>,
99     Self::Visitor: VisitOutput<Out>,
100 {
101     /// Visits all fields in `fields` with a new visitor constructed from
102     /// `target`.
visit_with<F>(&self, target: T, fields: &F) -> Out where F: RecordFields,103     fn visit_with<F>(&self, target: T, fields: &F) -> Out
104     where
105         F: RecordFields,
106     {
107         self.make_visitor(target).visit(fields)
108     }
109 }
110 
111 feature! {
112     #![feature = "std"]
113     use std::io;
114 
115     /// Extension trait implemented by visitors to indicate that they write to an
116     /// `io::Write` instance, and allow access to that writer.
117     pub trait VisitWrite: VisitOutput<Result<(), io::Error>> {
118         /// Returns the writer that this visitor writes to.
119         fn writer(&mut self) -> &mut dyn io::Write;
120     }
121 }
122 
123 /// Extension trait implemented by visitors to indicate that they write to a
124 /// `fmt::Write` instance, and allow access to that writer.
125 pub trait VisitFmt: VisitOutput<fmt::Result> {
126     /// Returns the formatter that this visitor writes to.
writer(&mut self) -> &mut dyn fmt::Write127     fn writer(&mut self) -> &mut dyn fmt::Write;
128 }
129 
130 /// Extension trait providing `MakeVisitor` combinators.
131 pub trait MakeExt<T>
132 where
133     Self: MakeVisitor<T> + Sized,
134     Self: crate::sealed::Sealed<MakeExtMarker<T>>,
135 {
136     /// Wraps `self` so that any `fmt::Debug` fields are recorded using the
137     /// alternate formatter (`{:#?}`).
debug_alt(self) -> debug::Alt<Self>138     fn debug_alt(self) -> debug::Alt<Self> {
139         debug::Alt::new(self)
140     }
141 
142     /// Wraps `self` so that any string fields named "message" are recorded
143     /// using `fmt::Display`.
display_messages(self) -> display::Messages<Self>144     fn display_messages(self) -> display::Messages<Self> {
145         display::Messages::new(self)
146     }
147 
148     /// Wraps `self` so that when fields are formatted to a writer, they are
149     /// separated by the provided `delimiter`.
delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self> where D: AsRef<str> + Clone, Self::Visitor: VisitFmt,150     fn delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self>
151     where
152         D: AsRef<str> + Clone,
153         Self::Visitor: VisitFmt,
154     {
155         delimited::Delimited::new(delimiter, self)
156     }
157 }
158 
159 // === impl RecordFields ===
160 
161 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {}
162 impl<'a> RecordFields for Event<'a> {
record(&self, visitor: &mut dyn Visit)163     fn record(&self, visitor: &mut dyn Visit) {
164         Event::record(self, visitor)
165     }
166 }
167 
168 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Attributes<'a> {}
169 impl<'a> RecordFields for Attributes<'a> {
record(&self, visitor: &mut dyn Visit)170     fn record(&self, visitor: &mut dyn Visit) {
171         Attributes::record(self, visitor)
172     }
173 }
174 
175 impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Record<'a> {}
176 impl<'a> RecordFields for Record<'a> {
record(&self, visitor: &mut dyn Visit)177     fn record(&self, visitor: &mut dyn Visit) {
178         Record::record(self, visitor)
179     }
180 }
181 
182 impl<'a, F> crate::sealed::Sealed<RecordFieldsMarker> for &'a F where F: RecordFields {}
183 impl<'a, F> RecordFields for &'a F
184 where
185     F: RecordFields,
186 {
record(&self, visitor: &mut dyn Visit)187     fn record(&self, visitor: &mut dyn Visit) {
188         F::record(*self, visitor)
189     }
190 }
191 
192 // === blanket impls ===
193 
194 impl<T, V, F> MakeVisitor<T> for F
195 where
196     F: Fn(T) -> V,
197     V: Visit,
198 {
199     type Visitor = V;
make_visitor(&self, target: T) -> Self::Visitor200     fn make_visitor(&self, target: T) -> Self::Visitor {
201         (self)(target)
202     }
203 }
204 
205 impl<T, Out, M> crate::sealed::Sealed<(T, Out)> for M
206 where
207     M: MakeVisitor<T>,
208     M::Visitor: VisitOutput<Out>,
209 {
210 }
211 
212 impl<T, Out, M> MakeOutput<T, Out> for M
213 where
214     M: MakeVisitor<T>,
215     M::Visitor: VisitOutput<Out>,
216 {
217 }
218 
219 impl<T, M> crate::sealed::Sealed<MakeExtMarker<T>> for M where M: MakeVisitor<T> + Sized {}
220 
221 impl<T, M> MakeExt<T> for M
222 where
223     M: MakeVisitor<T> + Sized,
224     M: crate::sealed::Sealed<MakeExtMarker<T>>,
225 {
226 }
227 
228 #[derive(Debug)]
229 #[doc(hidden)]
230 pub struct MakeExtMarker<T> {
231     _p: PhantomData<T>,
232 }
233 
234 #[derive(Debug)]
235 #[doc(hidden)]
236 pub struct RecordFieldsMarker {
237     _p: (),
238 }
239 
240 #[cfg(all(test, feature = "alloc"))]
241 #[macro_use]
242 pub(in crate::field) mod test_util {
243     use super::*;
244     pub(in crate::field) use alloc::string::String;
245     use tracing_core::{
246         callsite::Callsite,
247         field::{Field, Value},
248         metadata::{Kind, Level, Metadata},
249     };
250 
251     pub(crate) struct TestAttrs1;
252     pub(crate) struct TestAttrs2;
253 
254     impl TestAttrs1 {
with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T255         pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
256             let fieldset = TEST_META_1.fields();
257             let values = &[
258                 (
259                     &fieldset.field("question").unwrap(),
260                     Some(&"life, the universe, and everything" as &dyn Value),
261                 ),
262                 (&fieldset.field("question.answer").unwrap(), None),
263                 (
264                     &fieldset.field("tricky").unwrap(),
265                     Some(&true as &dyn Value),
266                 ),
267                 (
268                     &fieldset.field("can_you_do_it").unwrap(),
269                     Some(&true as &dyn Value),
270                 ),
271             ];
272             let valueset = fieldset.value_set(values);
273             let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
274             f(attrs)
275         }
276     }
277 
278     impl TestAttrs2 {
with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T279         pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
280             let fieldset = TEST_META_1.fields();
281             let none = tracing_core::field::debug(&Option::<&str>::None);
282             let values = &[
283                 (
284                     &fieldset.field("question").unwrap(),
285                     Some(&none as &dyn Value),
286                 ),
287                 (
288                     &fieldset.field("question.answer").unwrap(),
289                     Some(&42 as &dyn Value),
290                 ),
291                 (
292                     &fieldset.field("tricky").unwrap(),
293                     Some(&true as &dyn Value),
294                 ),
295                 (
296                     &fieldset.field("can_you_do_it").unwrap(),
297                     Some(&false as &dyn Value),
298                 ),
299             ];
300             let valueset = fieldset.value_set(values);
301             let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
302             f(attrs)
303         }
304     }
305 
306     struct TestCallsite1;
307     static TEST_CALLSITE_1: &'static dyn Callsite = &TestCallsite1;
308     static TEST_META_1: Metadata<'static> = tracing_core::metadata! {
309         name: "field_test1",
310         target: module_path!(),
311         level: Level::INFO,
312         fields: &["question", "question.answer", "tricky", "can_you_do_it"],
313         callsite: TEST_CALLSITE_1,
314         kind: Kind::SPAN,
315     };
316 
317     impl Callsite for TestCallsite1 {
set_interest(&self, _: tracing_core::subscriber::Interest)318         fn set_interest(&self, _: tracing_core::subscriber::Interest) {
319             unimplemented!()
320         }
321 
metadata(&self) -> &Metadata<'_>322         fn metadata(&self) -> &Metadata<'_> {
323             &TEST_META_1
324         }
325     }
326 
327     pub(crate) struct MakeDebug;
328     pub(crate) struct DebugVisitor<'a> {
329         writer: &'a mut dyn fmt::Write,
330         err: fmt::Result,
331     }
332 
333     impl<'a> DebugVisitor<'a> {
new(writer: &'a mut dyn fmt::Write) -> Self334         pub(crate) fn new(writer: &'a mut dyn fmt::Write) -> Self {
335             Self {
336                 writer,
337                 err: Ok(()),
338             }
339         }
340     }
341 
342     impl<'a> Visit for DebugVisitor<'a> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)343         fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
344             write!(self.writer, "{}={:?}", field, value).unwrap();
345         }
346     }
347 
348     impl<'a> VisitOutput<fmt::Result> for DebugVisitor<'a> {
finish(self) -> fmt::Result349         fn finish(self) -> fmt::Result {
350             self.err
351         }
352     }
353 
354     impl<'a> VisitFmt for DebugVisitor<'a> {
writer(&mut self) -> &mut dyn fmt::Write355         fn writer(&mut self) -> &mut dyn fmt::Write {
356             self.writer
357         }
358     }
359 
360     impl<'a> MakeVisitor<&'a mut dyn fmt::Write> for MakeDebug {
361         type Visitor = DebugVisitor<'a>;
make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a>362         fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> {
363             DebugVisitor::new(w)
364         }
365     }
366 }
367