1//! Utilities for working with [fields] and [field visitors].
2//!
3//! [fields]: tracing_core::field
4//! [field visitors]: tracing_core::field::Visit
5use core::{fmt, marker::PhantomData};
6pub use tracing_core::field::Visit;
7use tracing_core::{
8 span::{Attributes, Record},
9 Event,
10};
11pub mod debug;
12pub mod delimited;
13pub 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
26pub 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`.
31 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
37pub 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.
41 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.
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
88pub trait RecordFields: crate::sealed::Sealed<RecordFieldsMarker> {
89 /// Record all the fields in `self` with the provided `visitor`.
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`.
95pub trait MakeOutput<T, Out>
96where
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`.
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
110feature! {
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.
124pub trait VisitFmt: VisitOutput<fmt::Result> {
125 /// Returns the formatter that this visitor writes to.
126 fn writer(&mut self) -> &mut dyn fmt::Write;
127}
128
129/// Extension trait providing `MakeVisitor` combinators.
130pub trait MakeExt<T>
131where
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 (`{:#?}`).
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`.
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`.
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
160impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {}
161impl<'a> RecordFields for Event<'a> {
162 fn record(&self, visitor: &mut dyn Visit) {
163 Event::record(self, visitor)
164 }
165}
166
167impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Attributes<'a> {}
168impl<'a> RecordFields for Attributes<'a> {
169 fn record(&self, visitor: &mut dyn Visit) {
170 Attributes::record(self, visitor)
171 }
172}
173
174impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Record<'a> {}
175impl<'a> RecordFields for Record<'a> {
176 fn record(&self, visitor: &mut dyn Visit) {
177 Record::record(self, visitor)
178 }
179}
180
181impl<'a, F> crate::sealed::Sealed<RecordFieldsMarker> for &'a F where F: RecordFields {}
182impl<'a, F> RecordFields for &'a F
183where
184 F: RecordFields,
185{
186 fn record(&self, visitor: &mut dyn Visit) {
187 F::record(*self, visitor)
188 }
189}
190
191// === blanket impls ===
192
193impl<T, V, F> MakeVisitor<T> for F
194where
195 F: Fn(T) -> V,
196 V: Visit,
197{
198 type Visitor = V;
199 fn make_visitor(&self, target: T) -> Self::Visitor {
200 (self)(target)
201 }
202}
203
204impl<T, Out, M> crate::sealed::Sealed<(T, Out)> for M
205where
206 M: MakeVisitor<T>,
207 M::Visitor: VisitOutput<Out>,
208{
209}
210
211impl<T, Out, M> MakeOutput<T, Out> for M
212where
213 M: MakeVisitor<T>,
214 M::Visitor: VisitOutput<Out>,
215{
216}
217
218impl<T, M> crate::sealed::Sealed<MakeExtMarker<T>> for M where M: MakeVisitor<T> + Sized {}
219
220impl<T, M> MakeExt<T> for M
221where
222 M: MakeVisitor<T> + Sized,
223 M: crate::sealed::Sealed<MakeExtMarker<T>>,
224{
225}
226
227#[derive(Debug)]
228#[doc(hidden)]
229pub struct MakeExtMarker<T> {
230 _p: PhantomData<T>,
231}
232
233#[derive(Debug)]
234#[doc(hidden)]
235pub struct RecordFieldsMarker {
236 _p: (),
237}
238
239#[cfg(all(test, feature = "alloc"))]
240#[macro_use]
241pub(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 {
254 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 {
278 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 {
317 fn set_interest(&self, _: tracing_core::subscriber::Interest) {
318 unimplemented!()
319 }
320
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> {
333 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> {
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> {
348 fn finish(self) -> fmt::Result {
349 self.err
350 }
351 }
352
353 impl<'a> VisitFmt for DebugVisitor<'a> {
354 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>;
361 fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> {
362 DebugVisitor::new(w)
363 }
364 }
365}
366