| 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`. |
| 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 |
| 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. |
| 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 |
| 88 | pub 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`. |
| 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`. |
| 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. |
| 126 | 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 (`{:#?}`). |
| 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 | |
| 160 | impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {} |
| 161 | impl<'a> RecordFields for Event<'a> { |
| 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> { |
| 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> { |
| 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 | { |
| 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; |
| 199 | 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 { |
| 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 | |