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