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