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`] 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`. record(&self, visitor: &mut dyn Visit)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`. visit_with<F>(&self, target: T, fields: &F) -> Out where F: RecordFields,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. writer(&mut self) -> &mut dyn fmt::Write126 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 (`{:#?}`). debug_alt(self) -> debug::Alt<Self>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`. display_messages(self) -> display::Messages<Self>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`. delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self> where D: AsRef<str> + Clone, Self::Visitor: VisitFmt,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> { record(&self, visitor: &mut dyn Visit)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> { record(&self, visitor: &mut dyn Visit)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> { record(&self, visitor: &mut dyn Visit)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 { record(&self, visitor: &mut dyn Visit)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; make_visitor(&self, target: T) -> Self::Visitor199 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 { with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T254 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 { with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T278 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 { set_interest(&self, _: tracing_core::subscriber::Interest)317 fn set_interest(&self, _: tracing_core::subscriber::Interest) { 318 unimplemented!() 319 } 320 metadata(&self) -> &Metadata<'_>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> { new(writer: &'a mut dyn fmt::Write) -> Self333 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> { record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)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> { finish(self) -> fmt::Result348 fn finish(self) -> fmt::Result { 349 self.err 350 } 351 } 352 353 impl<'a> VisitFmt for DebugVisitor<'a> { writer(&mut self) -> &mut dyn fmt::Write354 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>; make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a>361 fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> { 362 DebugVisitor::new(w) 363 } 364 } 365 } 366