| 1 | //! `Span` and `Event` key-value data. |
| 2 | //! |
| 3 | //! Spans and events may be annotated with key-value data, known as _fields_. |
| 4 | //! These fields consist of a mapping from a key (corresponding to a `&str` but |
| 5 | //! represented internally as an array index) to a [`Value`]. |
| 6 | //! |
| 7 | //! # `Value`s and `Subscriber`s |
| 8 | //! |
| 9 | //! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s. |
| 10 | //! The set of field keys on a given span or event is defined on its [`Metadata`]. |
| 11 | //! When a span is created, it provides [`Attributes`] to the `Subscriber`'s |
| 12 | //! [`new_span`] method, containing any fields whose values were provided when |
| 13 | //! the span was created; and may call the `Subscriber`'s [`record`] method |
| 14 | //! with additional [`Record`]s if values are added for more of its fields. |
| 15 | //! Similarly, the [`Event`] type passed to the subscriber's [`event`] method |
| 16 | //! will contain any fields attached to each event. |
| 17 | //! |
| 18 | //! `tracing` represents values as either one of a set of Rust primitives |
| 19 | //! (`i64`, `u64`, `f64`, `i128`, `u128`, `bool`, and `&str`) or using a |
| 20 | //! `fmt::Display` or `fmt::Debug` implementation. `Subscriber`s are provided |
| 21 | //! these primitive value types as `dyn Value` trait objects. |
| 22 | //! |
| 23 | //! These trait objects can be formatted using `fmt::Debug`, but may also be |
| 24 | //! recorded as typed data by calling the [`Value::record`] method on these |
| 25 | //! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait |
| 26 | //! represents the behavior used to record values of various types. For example, |
| 27 | //! an implementation of `Visit` might record integers by incrementing counters |
| 28 | //! for their field names rather than printing them. |
| 29 | //! |
| 30 | //! |
| 31 | //! # Using `valuable` |
| 32 | //! |
| 33 | //! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small |
| 34 | //! number of Rust primitives as typed values, and only permits recording |
| 35 | //! user-defined types with their [`fmt::Debug`] or [`fmt::Display`] |
| 36 | //! implementations. However, there are some cases where it may be useful to record |
| 37 | //! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or |
| 38 | //! user-defined `struct` and `enum` types without having to format them as |
| 39 | //! unstructured text. |
| 40 | //! |
| 41 | //! To address `Value`'s limitations, `tracing` offers experimental support for |
| 42 | //! the [`valuable`] crate, which provides object-safe inspection of structured |
| 43 | //! values. User-defined types can implement the [`valuable::Valuable`] trait, |
| 44 | //! and be recorded as a `tracing` field by calling their [`as_value`] method. |
| 45 | //! If the [`Subscriber`] also supports the `valuable` crate, it can |
| 46 | //! then visit those types fields as structured values using `valuable`. |
| 47 | //! |
| 48 | //! <pre class="ignore" style="white-space:normal;font:inherit;"> |
| 49 | //! <strong>Note</strong>: <code>valuable</code> support is an |
| 50 | //! <a href = "../index.html#unstable-features">unstable feature</a>. See |
| 51 | //! the documentation on unstable features for details on how to enable it. |
| 52 | //! </pre> |
| 53 | //! |
| 54 | //! For example: |
| 55 | //! ```ignore |
| 56 | //! // Derive `Valuable` for our types: |
| 57 | //! use valuable::Valuable; |
| 58 | //! |
| 59 | //! #[derive(Clone, Debug, Valuable)] |
| 60 | //! struct User { |
| 61 | //! name: String, |
| 62 | //! age: u32, |
| 63 | //! address: Address, |
| 64 | //! } |
| 65 | //! |
| 66 | //! #[derive(Clone, Debug, Valuable)] |
| 67 | //! struct Address { |
| 68 | //! country: String, |
| 69 | //! city: String, |
| 70 | //! street: String, |
| 71 | //! } |
| 72 | //! |
| 73 | //! let user = User { |
| 74 | //! name: "Arwen Undomiel" .to_string(), |
| 75 | //! age: 3000, |
| 76 | //! address: Address { |
| 77 | //! country: "Middle Earth" .to_string(), |
| 78 | //! city: "Rivendell" .to_string(), |
| 79 | //! street: "leafy lane" .to_string(), |
| 80 | //! }, |
| 81 | //! }; |
| 82 | //! |
| 83 | //! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber |
| 84 | //! // to traverse its fields as a nested, typed structure: |
| 85 | //! tracing::info!(current_user = user.as_value()); |
| 86 | //! ``` |
| 87 | //! |
| 88 | //! Alternatively, the [`valuable()`] function may be used to convert a type |
| 89 | //! implementing [`Valuable`] into a `tracing` field value. |
| 90 | //! |
| 91 | //! When the `valuable` feature is enabled, the [`Visit`] trait will include an |
| 92 | //! optional [`record_value`] method. `Visit` implementations that wish to |
| 93 | //! record `valuable` values can implement this method with custom behavior. |
| 94 | //! If a visitor does not implement `record_value`, the [`valuable::Value`] will |
| 95 | //! be forwarded to the visitor's [`record_debug`] method. |
| 96 | //! |
| 97 | //! [`valuable`]: https://crates.io/crates/valuable |
| 98 | //! [`as_value`]: valuable::Valuable::as_value |
| 99 | //! [`Subscriber`]: crate::Subscriber |
| 100 | //! [`record_value`]: Visit::record_value |
| 101 | //! [`record_debug`]: Visit::record_debug |
| 102 | //! |
| 103 | //! [span]: super::span |
| 104 | //! [`Event`]: super::event::Event |
| 105 | //! [`Metadata`]: super::metadata::Metadata |
| 106 | //! [`Attributes`]: super::span::Attributes |
| 107 | //! [`Record`]: super::span::Record |
| 108 | //! [`new_span`]: super::subscriber::Subscriber::new_span |
| 109 | //! [`record`]: super::subscriber::Subscriber::record |
| 110 | //! [`event`]: super::subscriber::Subscriber::event |
| 111 | //! [`Value::record`]: Value::record |
| 112 | use crate::callsite; |
| 113 | use crate::stdlib::{ |
| 114 | borrow::Borrow, |
| 115 | fmt::{self, Write}, |
| 116 | hash::{Hash, Hasher}, |
| 117 | num, |
| 118 | ops::Range, |
| 119 | string::String, |
| 120 | }; |
| 121 | |
| 122 | use self::private::ValidLen; |
| 123 | |
| 124 | /// An opaque key allowing _O_(1) access to a field in a `Span`'s key-value |
| 125 | /// data. |
| 126 | /// |
| 127 | /// As keys are defined by the _metadata_ of a span, rather than by an |
| 128 | /// individual instance of a span, a key may be used to access the same field |
| 129 | /// across all instances of a given span with the same metadata. Thus, when a |
| 130 | /// subscriber observes a new span, it need only access a field by name _once_, |
| 131 | /// and use the key for that name for all other accesses. |
| 132 | #[derive (Debug)] |
| 133 | pub struct Field { |
| 134 | i: usize, |
| 135 | fields: FieldSet, |
| 136 | } |
| 137 | |
| 138 | /// An empty field. |
| 139 | /// |
| 140 | /// This can be used to indicate that the value of a field is not currently |
| 141 | /// present but will be recorded later. |
| 142 | /// |
| 143 | /// When a field's value is `Empty`. it will not be recorded. |
| 144 | #[derive (Debug, Eq, PartialEq)] |
| 145 | pub struct Empty; |
| 146 | |
| 147 | /// Describes the fields present on a span. |
| 148 | /// |
| 149 | /// ## Equality |
| 150 | /// |
| 151 | /// In well-behaved applications, two `FieldSet`s [initialized] with equal |
| 152 | /// [callsite identifiers] will have identical fields. Consequently, in release |
| 153 | /// builds, [`FieldSet::eq`] *only* checks that its arguments have equal |
| 154 | /// callsites. However, the equality of field names is checked in debug builds. |
| 155 | /// |
| 156 | /// [initialized]: Self::new |
| 157 | /// [callsite identifiers]: callsite::Identifier |
| 158 | pub struct FieldSet { |
| 159 | /// The names of each field on the described span. |
| 160 | names: &'static [&'static str], |
| 161 | /// The callsite where the described span originates. |
| 162 | callsite: callsite::Identifier, |
| 163 | } |
| 164 | |
| 165 | /// A set of fields and values for a span. |
| 166 | pub struct ValueSet<'a> { |
| 167 | values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)], |
| 168 | fields: &'a FieldSet, |
| 169 | } |
| 170 | |
| 171 | /// An iterator over a set of fields. |
| 172 | #[derive (Debug)] |
| 173 | pub struct Iter { |
| 174 | idxs: Range<usize>, |
| 175 | fields: FieldSet, |
| 176 | } |
| 177 | |
| 178 | /// Visits typed values. |
| 179 | /// |
| 180 | /// An instance of `Visit` ("a visitor") represents the logic necessary to |
| 181 | /// record field values of various types. When an implementor of [`Value`] is |
| 182 | /// [recorded], it calls the appropriate method on the provided visitor to |
| 183 | /// indicate the type that value should be recorded as. |
| 184 | /// |
| 185 | /// When a [`Subscriber`] implementation [records an `Event`] or a |
| 186 | /// [set of `Value`s added to a `Span`], it can pass an `&mut Visit` to the |
| 187 | /// `record` method on the provided [`ValueSet`] or [`Event`]. This visitor |
| 188 | /// will then be used to record all the field-value pairs present on that |
| 189 | /// `Event` or `ValueSet`. |
| 190 | /// |
| 191 | /// # Examples |
| 192 | /// |
| 193 | /// A simple visitor that writes to a string might be implemented like so: |
| 194 | /// ``` |
| 195 | /// # extern crate tracing_core as tracing; |
| 196 | /// use std::fmt::{self, Write}; |
| 197 | /// use tracing::field::{Value, Visit, Field}; |
| 198 | /// pub struct StringVisitor<'a> { |
| 199 | /// string: &'a mut String, |
| 200 | /// } |
| 201 | /// |
| 202 | /// impl<'a> Visit for StringVisitor<'a> { |
| 203 | /// fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { |
| 204 | /// write!(self.string, "{} = {:?}; " , field.name(), value).unwrap(); |
| 205 | /// } |
| 206 | /// } |
| 207 | /// ``` |
| 208 | /// This visitor will format each recorded value using `fmt::Debug`, and |
| 209 | /// append the field name and formatted value to the provided string, |
| 210 | /// regardless of the type of the recorded value. When all the values have |
| 211 | /// been recorded, the `StringVisitor` may be dropped, allowing the string |
| 212 | /// to be printed or stored in some other data structure. |
| 213 | /// |
| 214 | /// The `Visit` trait provides default implementations for `record_i64`, |
| 215 | /// `record_u64`, `record_bool`, `record_str`, and `record_error`, which simply |
| 216 | /// forward the recorded value to `record_debug`. Thus, `record_debug` is the |
| 217 | /// only method which a `Visit` implementation *must* implement. However, |
| 218 | /// visitors may override the default implementations of these functions in |
| 219 | /// order to implement type-specific behavior. |
| 220 | /// |
| 221 | /// Additionally, when a visitor receives a value of a type it does not care |
| 222 | /// about, it is free to ignore those values completely. For example, a |
| 223 | /// visitor which only records numeric data might look like this: |
| 224 | /// |
| 225 | /// ``` |
| 226 | /// # extern crate tracing_core as tracing; |
| 227 | /// # use std::fmt::{self, Write}; |
| 228 | /// # use tracing::field::{Value, Visit, Field}; |
| 229 | /// pub struct SumVisitor { |
| 230 | /// sum: i64, |
| 231 | /// } |
| 232 | /// |
| 233 | /// impl Visit for SumVisitor { |
| 234 | /// fn record_i64(&mut self, _field: &Field, value: i64) { |
| 235 | /// self.sum += value; |
| 236 | /// } |
| 237 | /// |
| 238 | /// fn record_u64(&mut self, _field: &Field, value: u64) { |
| 239 | /// self.sum += value as i64; |
| 240 | /// } |
| 241 | /// |
| 242 | /// fn record_debug(&mut self, _field: &Field, _value: &fmt::Debug) { |
| 243 | /// // Do nothing |
| 244 | /// } |
| 245 | /// } |
| 246 | /// ``` |
| 247 | /// |
| 248 | /// This visitor (which is probably not particularly useful) keeps a running |
| 249 | /// sum of all the numeric values it records, and ignores all other values. A |
| 250 | /// more practical example of recording typed values is presented in |
| 251 | /// `examples/counters.rs`, which demonstrates a very simple metrics system |
| 252 | /// implemented using `tracing`. |
| 253 | /// |
| 254 | /// <div class="example-wrap" style="display:inline-block"> |
| 255 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
| 256 | /// <strong>Note</strong>: The <code>record_error</code> trait method is only |
| 257 | /// available when the Rust standard library is present, as it requires the |
| 258 | /// <code>std::error::Error</code> trait. |
| 259 | /// </pre></div> |
| 260 | /// |
| 261 | /// [recorded]: Value::record |
| 262 | /// [`Subscriber`]: super::subscriber::Subscriber |
| 263 | /// [records an `Event`]: super::subscriber::Subscriber::event |
| 264 | /// [set of `Value`s added to a `Span`]: super::subscriber::Subscriber::record |
| 265 | /// [`Event`]: super::event::Event |
| 266 | pub trait Visit { |
| 267 | /// Visits an arbitrary type implementing the [`valuable`] crate's `Valuable` trait. |
| 268 | /// |
| 269 | /// [`valuable`]: https://docs.rs/valuable |
| 270 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 271 | #[cfg_attr (docsrs, doc(cfg(all(tracing_unstable, feature = "valuable" ))))] |
| 272 | fn record_value(&mut self, field: &Field, value: valuable::Value<'_>) { |
| 273 | self.record_debug(field, &value) |
| 274 | } |
| 275 | |
| 276 | /// Visit a double-precision floating point value. |
| 277 | fn record_f64(&mut self, field: &Field, value: f64) { |
| 278 | self.record_debug(field, &value) |
| 279 | } |
| 280 | |
| 281 | /// Visit a signed 64-bit integer value. |
| 282 | fn record_i64(&mut self, field: &Field, value: i64) { |
| 283 | self.record_debug(field, &value) |
| 284 | } |
| 285 | |
| 286 | /// Visit an unsigned 64-bit integer value. |
| 287 | fn record_u64(&mut self, field: &Field, value: u64) { |
| 288 | self.record_debug(field, &value) |
| 289 | } |
| 290 | |
| 291 | /// Visit a signed 128-bit integer value. |
| 292 | fn record_i128(&mut self, field: &Field, value: i128) { |
| 293 | self.record_debug(field, &value) |
| 294 | } |
| 295 | |
| 296 | /// Visit an unsigned 128-bit integer value. |
| 297 | fn record_u128(&mut self, field: &Field, value: u128) { |
| 298 | self.record_debug(field, &value) |
| 299 | } |
| 300 | |
| 301 | /// Visit a boolean value. |
| 302 | fn record_bool(&mut self, field: &Field, value: bool) { |
| 303 | self.record_debug(field, &value) |
| 304 | } |
| 305 | |
| 306 | /// Visit a string value. |
| 307 | fn record_str(&mut self, field: &Field, value: &str) { |
| 308 | self.record_debug(field, &value) |
| 309 | } |
| 310 | |
| 311 | /// Visit a byte slice. |
| 312 | fn record_bytes(&mut self, field: &Field, value: &[u8]) { |
| 313 | self.record_debug(field, &HexBytes(value)) |
| 314 | } |
| 315 | |
| 316 | /// Records a type implementing `Error`. |
| 317 | /// |
| 318 | /// <div class="example-wrap" style="display:inline-block"> |
| 319 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
| 320 | /// <strong>Note</strong>: This is only enabled when the Rust standard library is |
| 321 | /// present. |
| 322 | /// </pre> |
| 323 | /// </div> |
| 324 | #[cfg (feature = "std" )] |
| 325 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 326 | fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) { |
| 327 | self.record_debug(field, &DisplayValue(value)) |
| 328 | } |
| 329 | |
| 330 | /// Visit a value implementing `fmt::Debug`. |
| 331 | fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug); |
| 332 | } |
| 333 | |
| 334 | /// A field value of an erased type. |
| 335 | /// |
| 336 | /// Implementors of `Value` may call the appropriate typed recording methods on |
| 337 | /// the [visitor] passed to their `record` method in order to indicate how |
| 338 | /// their data should be recorded. |
| 339 | /// |
| 340 | /// [visitor]: Visit |
| 341 | pub trait Value: crate::sealed::Sealed { |
| 342 | /// Visits this value with the given `Visitor`. |
| 343 | fn record(&self, key: &Field, visitor: &mut dyn Visit); |
| 344 | } |
| 345 | |
| 346 | /// A `Value` which serializes using `fmt::Display`. |
| 347 | /// |
| 348 | /// Uses `record_debug` in the `Value` implementation to |
| 349 | /// avoid an unnecessary evaluation. |
| 350 | #[derive (Clone)] |
| 351 | pub struct DisplayValue<T: fmt::Display>(T); |
| 352 | |
| 353 | /// A `Value` which serializes as a string using `fmt::Debug`. |
| 354 | #[derive (Clone)] |
| 355 | pub struct DebugValue<T: fmt::Debug>(T); |
| 356 | |
| 357 | /// Wraps a type implementing `fmt::Display` as a `Value` that can be |
| 358 | /// recorded using its `Display` implementation. |
| 359 | pub fn display<T>(t: T) -> DisplayValue<T> |
| 360 | where |
| 361 | T: fmt::Display, |
| 362 | { |
| 363 | DisplayValue(t) |
| 364 | } |
| 365 | |
| 366 | /// Wraps a type implementing `fmt::Debug` as a `Value` that can be |
| 367 | /// recorded using its `Debug` implementation. |
| 368 | pub fn debug<T>(t: T) -> DebugValue<T> |
| 369 | where |
| 370 | T: fmt::Debug, |
| 371 | { |
| 372 | DebugValue(t) |
| 373 | } |
| 374 | |
| 375 | /// Wraps a type implementing [`Valuable`] as a `Value` that |
| 376 | /// can be recorded using its `Valuable` implementation. |
| 377 | /// |
| 378 | /// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html |
| 379 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 380 | #[cfg_attr (docsrs, doc(cfg(all(tracing_unstable, feature = "valuable" ))))] |
| 381 | pub fn valuable<T>(t: &T) -> valuable::Value<'_> |
| 382 | where |
| 383 | T: valuable::Valuable, |
| 384 | { |
| 385 | t.as_value() |
| 386 | } |
| 387 | |
| 388 | struct HexBytes<'a>(&'a [u8]); |
| 389 | |
| 390 | impl<'a> fmt::Debug for HexBytes<'a> { |
| 391 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 392 | f.write_char('[' )?; |
| 393 | |
| 394 | let mut bytes: Iter<'_, u8> = self.0.iter(); |
| 395 | |
| 396 | if let Some(byte: &u8) = bytes.next() { |
| 397 | f.write_fmt(format_args!(" {byte:02x}" ))?; |
| 398 | } |
| 399 | |
| 400 | for byte: &u8 in bytes { |
| 401 | f.write_fmt(format_args!(" {byte:02x}" ))?; |
| 402 | } |
| 403 | |
| 404 | f.write_char(']' ) |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | // ===== impl Visit ===== |
| 409 | |
| 410 | impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> { |
| 411 | fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { |
| 412 | self.field(field.name(), value); |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> { |
| 417 | fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { |
| 418 | self.entry(&format_args!(" {}" , field), value); |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | impl<F> Visit for F |
| 423 | where |
| 424 | F: FnMut(&Field, &dyn fmt::Debug), |
| 425 | { |
| 426 | fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { |
| 427 | (self)(field, value) |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | // ===== impl Value ===== |
| 432 | |
| 433 | macro_rules! impl_values { |
| 434 | ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => { |
| 435 | $( |
| 436 | impl_value!{ $record( $( $whatever )+ ) } |
| 437 | )+ |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | macro_rules! ty_to_nonzero { |
| 442 | (u8) => { |
| 443 | NonZeroU8 |
| 444 | }; |
| 445 | (u16) => { |
| 446 | NonZeroU16 |
| 447 | }; |
| 448 | (u32) => { |
| 449 | NonZeroU32 |
| 450 | }; |
| 451 | (u64) => { |
| 452 | NonZeroU64 |
| 453 | }; |
| 454 | (u128) => { |
| 455 | NonZeroU128 |
| 456 | }; |
| 457 | (usize) => { |
| 458 | NonZeroUsize |
| 459 | }; |
| 460 | (i8) => { |
| 461 | NonZeroI8 |
| 462 | }; |
| 463 | (i16) => { |
| 464 | NonZeroI16 |
| 465 | }; |
| 466 | (i32) => { |
| 467 | NonZeroI32 |
| 468 | }; |
| 469 | (i64) => { |
| 470 | NonZeroI64 |
| 471 | }; |
| 472 | (i128) => { |
| 473 | NonZeroI128 |
| 474 | }; |
| 475 | (isize) => { |
| 476 | NonZeroIsize |
| 477 | }; |
| 478 | } |
| 479 | |
| 480 | macro_rules! impl_one_value { |
| 481 | (f32, $op:expr, $record:ident) => { |
| 482 | impl_one_value!(normal, f32, $op, $record); |
| 483 | }; |
| 484 | (f64, $op:expr, $record:ident) => { |
| 485 | impl_one_value!(normal, f64, $op, $record); |
| 486 | }; |
| 487 | (bool, $op:expr, $record:ident) => { |
| 488 | impl_one_value!(normal, bool, $op, $record); |
| 489 | }; |
| 490 | ($value_ty:tt, $op:expr, $record:ident) => { |
| 491 | impl_one_value!(normal, $value_ty, $op, $record); |
| 492 | impl_one_value!(nonzero, $value_ty, $op, $record); |
| 493 | }; |
| 494 | (normal, $value_ty:tt, $op:expr, $record:ident) => { |
| 495 | impl $crate::sealed::Sealed for $value_ty {} |
| 496 | impl $crate::field::Value for $value_ty { |
| 497 | fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) { |
| 498 | // `op` is always a function; the closure is used because |
| 499 | // sometimes there isn't a real function corresponding to that |
| 500 | // operation. the clippy warning is not that useful here. |
| 501 | #[allow(clippy::redundant_closure_call)] |
| 502 | visitor.$record(key, $op(*self)) |
| 503 | } |
| 504 | } |
| 505 | }; |
| 506 | (nonzero, $value_ty:tt, $op:expr, $record:ident) => { |
| 507 | // This `use num::*;` is reported as unused because it gets emitted |
| 508 | // for every single invocation of this macro, so there are multiple `use`s. |
| 509 | // All but the first are useless indeed. |
| 510 | // We need this import because we can't write a path where one part is |
| 511 | // the `ty_to_nonzero!($value_ty)` invocation. |
| 512 | #[allow(clippy::useless_attribute, unused)] |
| 513 | use num::*; |
| 514 | impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {} |
| 515 | impl $crate::field::Value for ty_to_nonzero!($value_ty) { |
| 516 | fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) { |
| 517 | // `op` is always a function; the closure is used because |
| 518 | // sometimes there isn't a real function corresponding to that |
| 519 | // operation. the clippy warning is not that useful here. |
| 520 | #[allow(clippy::redundant_closure_call)] |
| 521 | visitor.$record(key, $op(self.get())) |
| 522 | } |
| 523 | } |
| 524 | }; |
| 525 | } |
| 526 | |
| 527 | macro_rules! impl_value { |
| 528 | ( $record:ident( $( $value_ty:tt ),+ ) ) => { |
| 529 | $( |
| 530 | impl_one_value!($value_ty, |this: $value_ty| this, $record); |
| 531 | )+ |
| 532 | }; |
| 533 | ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => { |
| 534 | $( |
| 535 | impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record); |
| 536 | )+ |
| 537 | }; |
| 538 | } |
| 539 | |
| 540 | // ===== impl Value ===== |
| 541 | |
| 542 | impl_values! { |
| 543 | record_u64(u64), |
| 544 | record_u64(usize, u32, u16, u8 as u64), |
| 545 | record_i64(i64), |
| 546 | record_i64(isize, i32, i16, i8 as i64), |
| 547 | record_u128(u128), |
| 548 | record_i128(i128), |
| 549 | record_bool(bool), |
| 550 | record_f64(f64, f32 as f64) |
| 551 | } |
| 552 | |
| 553 | impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {} |
| 554 | impl<T: crate::field::Value> crate::field::Value for Wrapping<T> { |
| 555 | fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) { |
| 556 | self.0.record(key, visitor) |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | impl crate::sealed::Sealed for str {} |
| 561 | |
| 562 | impl Value for str { |
| 563 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 564 | visitor.record_str(field:key, self) |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | impl crate::sealed::Sealed for [u8] {} |
| 569 | |
| 570 | impl Value for [u8] { |
| 571 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 572 | visitor.record_bytes(field:key, self) |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | #[cfg (feature = "std" )] |
| 577 | impl crate::sealed::Sealed for dyn std::error::Error + 'static {} |
| 578 | |
| 579 | #[cfg (feature = "std" )] |
| 580 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 581 | impl Value for dyn std::error::Error + 'static { |
| 582 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 583 | visitor.record_error(field:key, self) |
| 584 | } |
| 585 | } |
| 586 | |
| 587 | #[cfg (feature = "std" )] |
| 588 | impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {} |
| 589 | |
| 590 | #[cfg (feature = "std" )] |
| 591 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 592 | impl Value for dyn std::error::Error + Send + 'static { |
| 593 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 594 | (self as &dyn std::error::Error).record(key, visitor) |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | #[cfg (feature = "std" )] |
| 599 | impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {} |
| 600 | |
| 601 | #[cfg (feature = "std" )] |
| 602 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 603 | impl Value for dyn std::error::Error + Sync + 'static { |
| 604 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 605 | (self as &dyn std::error::Error).record(key, visitor) |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | #[cfg (feature = "std" )] |
| 610 | impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {} |
| 611 | |
| 612 | #[cfg (feature = "std" )] |
| 613 | #[cfg_attr (docsrs, doc(cfg(feature = "std" )))] |
| 614 | impl Value for dyn std::error::Error + Send + Sync + 'static { |
| 615 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 616 | (self as &dyn std::error::Error).record(key, visitor) |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {} |
| 621 | |
| 622 | impl<'a, T: ?Sized> Value for &'a T |
| 623 | where |
| 624 | T: Value + 'a, |
| 625 | { |
| 626 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 627 | (*self).record(key, visitor) |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {} |
| 632 | |
| 633 | impl<'a, T: ?Sized> Value for &'a mut T |
| 634 | where |
| 635 | T: Value + 'a, |
| 636 | { |
| 637 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 638 | // Don't use `(*self).record(key, visitor)`, otherwise would |
| 639 | // cause stack overflow due to `unconditional_recursion`. |
| 640 | T::record(self, key, visitor) |
| 641 | } |
| 642 | } |
| 643 | |
| 644 | impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {} |
| 645 | |
| 646 | impl<'a> Value for fmt::Arguments<'a> { |
| 647 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 648 | visitor.record_debug(field:key, self) |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {} |
| 653 | |
| 654 | impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T> |
| 655 | where |
| 656 | T: Value, |
| 657 | { |
| 658 | #[inline ] |
| 659 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 660 | self.as_ref().record(key, visitor) |
| 661 | } |
| 662 | } |
| 663 | |
| 664 | impl crate::sealed::Sealed for String {} |
| 665 | impl Value for String { |
| 666 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 667 | visitor.record_str(field:key, self.as_str()) |
| 668 | } |
| 669 | } |
| 670 | |
| 671 | impl fmt::Debug for dyn Value { |
| 672 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 673 | // We are only going to be recording the field value, so we don't |
| 674 | // actually care about the field name here. |
| 675 | struct NullCallsite; |
| 676 | static NULL_CALLSITE: NullCallsite = NullCallsite; |
| 677 | impl crate::callsite::Callsite for NullCallsite { |
| 678 | fn set_interest(&self, _: crate::subscriber::Interest) { |
| 679 | unreachable!("you somehow managed to register the null callsite?" ) |
| 680 | } |
| 681 | |
| 682 | fn metadata(&self) -> &crate::Metadata<'_> { |
| 683 | unreachable!("you somehow managed to access the null callsite?" ) |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | static FIELD: Field = Field { |
| 688 | i: 0, |
| 689 | fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)), |
| 690 | }; |
| 691 | |
| 692 | let mut res = Ok(()); |
| 693 | self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| { |
| 694 | res = write!(f, " {:?}" , val); |
| 695 | }); |
| 696 | res |
| 697 | } |
| 698 | } |
| 699 | |
| 700 | impl fmt::Display for dyn Value { |
| 701 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 702 | fmt::Debug::fmt(self, f) |
| 703 | } |
| 704 | } |
| 705 | |
| 706 | // ===== impl DisplayValue ===== |
| 707 | |
| 708 | impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {} |
| 709 | |
| 710 | impl<T> Value for DisplayValue<T> |
| 711 | where |
| 712 | T: fmt::Display, |
| 713 | { |
| 714 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 715 | visitor.record_debug(field:key, self) |
| 716 | } |
| 717 | } |
| 718 | |
| 719 | impl<T: fmt::Display> fmt::Debug for DisplayValue<T> { |
| 720 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 721 | fmt::Display::fmt(self, f) |
| 722 | } |
| 723 | } |
| 724 | |
| 725 | impl<T: fmt::Display> fmt::Display for DisplayValue<T> { |
| 726 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 727 | self.0.fmt(f) |
| 728 | } |
| 729 | } |
| 730 | |
| 731 | // ===== impl DebugValue ===== |
| 732 | |
| 733 | impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {} |
| 734 | |
| 735 | impl<T> Value for DebugValue<T> |
| 736 | where |
| 737 | T: fmt::Debug, |
| 738 | { |
| 739 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 740 | visitor.record_debug(field:key, &self.0) |
| 741 | } |
| 742 | } |
| 743 | |
| 744 | impl<T: fmt::Debug> fmt::Debug for DebugValue<T> { |
| 745 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 746 | self.0.fmt(f) |
| 747 | } |
| 748 | } |
| 749 | |
| 750 | // ===== impl ValuableValue ===== |
| 751 | |
| 752 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 753 | impl crate::sealed::Sealed for valuable::Value<'_> {} |
| 754 | |
| 755 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 756 | #[cfg_attr (docsrs, doc(cfg(all(tracing_unstable, feature = "valuable" ))))] |
| 757 | impl Value for valuable::Value<'_> { |
| 758 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 759 | visitor.record_value(key, *self) |
| 760 | } |
| 761 | } |
| 762 | |
| 763 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 764 | impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {} |
| 765 | |
| 766 | #[cfg (all(tracing_unstable, feature = "valuable" ))] |
| 767 | #[cfg_attr (docsrs, doc(cfg(all(tracing_unstable, feature = "valuable" ))))] |
| 768 | impl Value for &'_ dyn valuable::Valuable { |
| 769 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 770 | visitor.record_value(key, self.as_value()) |
| 771 | } |
| 772 | } |
| 773 | |
| 774 | impl crate::sealed::Sealed for Empty {} |
| 775 | impl Value for Empty { |
| 776 | #[inline ] |
| 777 | fn record(&self, _: &Field, _: &mut dyn Visit) {} |
| 778 | } |
| 779 | |
| 780 | impl<T: Value> crate::sealed::Sealed for Option<T> {} |
| 781 | |
| 782 | impl<T: Value> Value for Option<T> { |
| 783 | fn record(&self, key: &Field, visitor: &mut dyn Visit) { |
| 784 | if let Some(v: &T) = &self { |
| 785 | v.record(key, visitor) |
| 786 | } |
| 787 | } |
| 788 | } |
| 789 | |
| 790 | // ===== impl Field ===== |
| 791 | |
| 792 | impl Field { |
| 793 | /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`] |
| 794 | /// which defines this field. |
| 795 | /// |
| 796 | /// [`Identifier`]: super::callsite::Identifier |
| 797 | /// [`Callsite`]: super::callsite::Callsite |
| 798 | #[inline ] |
| 799 | pub fn callsite(&self) -> callsite::Identifier { |
| 800 | self.fields.callsite() |
| 801 | } |
| 802 | |
| 803 | /// Returns a string representing the name of the field. |
| 804 | pub fn name(&self) -> &'static str { |
| 805 | self.fields.names[self.i] |
| 806 | } |
| 807 | |
| 808 | /// Returns the index of this field in its [`FieldSet`]. |
| 809 | pub fn index(&self) -> usize { |
| 810 | self.i |
| 811 | } |
| 812 | } |
| 813 | |
| 814 | impl fmt::Display for Field { |
| 815 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 816 | f.pad(self.name()) |
| 817 | } |
| 818 | } |
| 819 | |
| 820 | impl AsRef<str> for Field { |
| 821 | fn as_ref(&self) -> &str { |
| 822 | self.name() |
| 823 | } |
| 824 | } |
| 825 | |
| 826 | impl PartialEq for Field { |
| 827 | fn eq(&self, other: &Self) -> bool { |
| 828 | self.callsite() == other.callsite() && self.i == other.i |
| 829 | } |
| 830 | } |
| 831 | |
| 832 | impl Eq for Field {} |
| 833 | |
| 834 | impl Hash for Field { |
| 835 | fn hash<H>(&self, state: &mut H) |
| 836 | where |
| 837 | H: Hasher, |
| 838 | { |
| 839 | self.callsite().hash(state); |
| 840 | self.i.hash(state); |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | impl Clone for Field { |
| 845 | fn clone(&self) -> Self { |
| 846 | Field { |
| 847 | i: self.i, |
| 848 | fields: FieldSet { |
| 849 | names: self.fields.names, |
| 850 | callsite: self.fields.callsite(), |
| 851 | }, |
| 852 | } |
| 853 | } |
| 854 | } |
| 855 | |
| 856 | // ===== impl FieldSet ===== |
| 857 | |
| 858 | impl FieldSet { |
| 859 | /// Constructs a new `FieldSet` with the given array of field names and callsite. |
| 860 | pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self { |
| 861 | Self { names, callsite } |
| 862 | } |
| 863 | |
| 864 | /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`] |
| 865 | /// which defines this set of fields.. |
| 866 | /// |
| 867 | /// [`Identifier`]: super::callsite::Identifier |
| 868 | /// [`Callsite`]: super::callsite::Callsite |
| 869 | #[inline ] |
| 870 | pub(crate) fn callsite(&self) -> callsite::Identifier { |
| 871 | callsite::Identifier(self.callsite.0) |
| 872 | } |
| 873 | |
| 874 | /// Returns the [`Field`] named `name`, or `None` if no such field exists. |
| 875 | /// |
| 876 | /// [`Field`]: super::Field |
| 877 | pub fn field<Q: Borrow<str> + ?Sized>(&self, name: &Q) -> Option<Field> { |
| 878 | let name = &name.borrow(); |
| 879 | self.names.iter().position(|f| f == name).map(|i| Field { |
| 880 | i, |
| 881 | fields: FieldSet { |
| 882 | names: self.names, |
| 883 | callsite: self.callsite(), |
| 884 | }, |
| 885 | }) |
| 886 | } |
| 887 | |
| 888 | /// Returns `true` if `self` contains the given `field`. |
| 889 | /// |
| 890 | /// <div class="example-wrap" style="display:inline-block"> |
| 891 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
| 892 | /// <strong>Note</strong>: If <code>field</code> shares a name with a field |
| 893 | /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code> |
| 894 | /// with a different callsite, this <code>FieldSet</code> does <em>not</em> |
| 895 | /// contain it. This is so that if two separate span callsites define a field |
| 896 | /// named "foo", the <code>Field</code> corresponding to "foo" for each |
| 897 | /// of those callsites are not equivalent. |
| 898 | /// </pre></div> |
| 899 | pub fn contains(&self, field: &Field) -> bool { |
| 900 | field.callsite() == self.callsite() && field.i <= self.len() |
| 901 | } |
| 902 | |
| 903 | /// Returns an iterator over the `Field`s in this `FieldSet`. |
| 904 | #[inline ] |
| 905 | pub fn iter(&self) -> Iter { |
| 906 | let idxs = 0..self.len(); |
| 907 | Iter { |
| 908 | idxs, |
| 909 | fields: FieldSet { |
| 910 | names: self.names, |
| 911 | callsite: self.callsite(), |
| 912 | }, |
| 913 | } |
| 914 | } |
| 915 | |
| 916 | /// Returns a new `ValueSet` with entries for this `FieldSet`'s values. |
| 917 | #[doc (hidden)] |
| 918 | pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> |
| 919 | where |
| 920 | V: ValidLen<'v>, |
| 921 | { |
| 922 | ValueSet { |
| 923 | fields: self, |
| 924 | values: values.borrow(), |
| 925 | } |
| 926 | } |
| 927 | |
| 928 | /// Returns the number of fields in this `FieldSet`. |
| 929 | #[inline ] |
| 930 | pub fn len(&self) -> usize { |
| 931 | self.names.len() |
| 932 | } |
| 933 | |
| 934 | /// Returns whether or not this `FieldSet` has fields. |
| 935 | #[inline ] |
| 936 | pub fn is_empty(&self) -> bool { |
| 937 | self.names.is_empty() |
| 938 | } |
| 939 | } |
| 940 | |
| 941 | impl<'a> IntoIterator for &'a FieldSet { |
| 942 | type IntoIter = Iter; |
| 943 | type Item = Field; |
| 944 | #[inline ] |
| 945 | fn into_iter(self) -> Self::IntoIter { |
| 946 | self.iter() |
| 947 | } |
| 948 | } |
| 949 | |
| 950 | impl fmt::Debug for FieldSet { |
| 951 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 952 | f&mut DebugStruct<'_, '_>.debug_struct("FieldSet" ) |
| 953 | .field("names" , &self.names) |
| 954 | .field(name:"callsite" , &self.callsite) |
| 955 | .finish() |
| 956 | } |
| 957 | } |
| 958 | |
| 959 | impl fmt::Display for FieldSet { |
| 960 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 961 | f&mut DebugSet<'_, '_>.debug_set() |
| 962 | .entries(self.names.iter().map(display)) |
| 963 | .finish() |
| 964 | } |
| 965 | } |
| 966 | |
| 967 | impl Eq for FieldSet {} |
| 968 | |
| 969 | impl PartialEq for FieldSet { |
| 970 | fn eq(&self, other: &Self) -> bool { |
| 971 | if core::ptr::eq(&self, &other) { |
| 972 | true |
| 973 | } else if cfg!(not(debug_assertions)) { |
| 974 | // In a well-behaving application, two `FieldSet`s can be assumed to |
| 975 | // be totally equal so long as they share the same callsite. |
| 976 | self.callsite == other.callsite |
| 977 | } else { |
| 978 | // However, when debug-assertions are enabled, do NOT assume that |
| 979 | // the application is well-behaving; check every the field names of |
| 980 | // each `FieldSet` for equality. |
| 981 | |
| 982 | // `FieldSet` is destructured here to ensure a compile-error if the |
| 983 | // fields of `FieldSet` change. |
| 984 | let Self { |
| 985 | names: lhs_names, |
| 986 | callsite: lhs_callsite, |
| 987 | } = self; |
| 988 | |
| 989 | let Self { |
| 990 | names: rhs_names, |
| 991 | callsite: rhs_callsite, |
| 992 | } = &other; |
| 993 | |
| 994 | // Check callsite equality first, as it is probably cheaper to do |
| 995 | // than str equality. |
| 996 | lhs_callsite == rhs_callsite && lhs_names == rhs_names |
| 997 | } |
| 998 | } |
| 999 | } |
| 1000 | |
| 1001 | // ===== impl Iter ===== |
| 1002 | |
| 1003 | impl Iterator for Iter { |
| 1004 | type Item = Field; |
| 1005 | #[inline ] |
| 1006 | fn next(&mut self) -> Option<Field> { |
| 1007 | let i: usize = self.idxs.next()?; |
| 1008 | Some(Field { |
| 1009 | i, |
| 1010 | fields: FieldSet { |
| 1011 | names: self.fields.names, |
| 1012 | callsite: self.fields.callsite(), |
| 1013 | }, |
| 1014 | }) |
| 1015 | } |
| 1016 | } |
| 1017 | |
| 1018 | // ===== impl ValueSet ===== |
| 1019 | |
| 1020 | impl<'a> ValueSet<'a> { |
| 1021 | /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`] |
| 1022 | /// defining the fields this `ValueSet` refers to. |
| 1023 | /// |
| 1024 | /// [`Identifier`]: super::callsite::Identifier |
| 1025 | /// [`Callsite`]: super::callsite::Callsite |
| 1026 | #[inline ] |
| 1027 | pub fn callsite(&self) -> callsite::Identifier { |
| 1028 | self.fields.callsite() |
| 1029 | } |
| 1030 | |
| 1031 | /// Visits all the fields in this `ValueSet` with the provided [visitor]. |
| 1032 | /// |
| 1033 | /// [visitor]: Visit |
| 1034 | pub fn record(&self, visitor: &mut dyn Visit) { |
| 1035 | let my_callsite = self.callsite(); |
| 1036 | for (field, value) in self.values { |
| 1037 | if field.callsite() != my_callsite { |
| 1038 | continue; |
| 1039 | } |
| 1040 | if let Some(value) = value { |
| 1041 | value.record(field, visitor); |
| 1042 | } |
| 1043 | } |
| 1044 | } |
| 1045 | |
| 1046 | /// Returns the number of fields in this `ValueSet` that would be visited |
| 1047 | /// by a given [visitor] to the [`ValueSet::record()`] method. |
| 1048 | /// |
| 1049 | /// [visitor]: Visit |
| 1050 | /// [`ValueSet::record()`]: ValueSet::record() |
| 1051 | pub fn len(&self) -> usize { |
| 1052 | let my_callsite = self.callsite(); |
| 1053 | self.values |
| 1054 | .iter() |
| 1055 | .filter(|(field, _)| field.callsite() == my_callsite) |
| 1056 | .count() |
| 1057 | } |
| 1058 | |
| 1059 | /// Returns `true` if this `ValueSet` contains a value for the given `Field`. |
| 1060 | pub(crate) fn contains(&self, field: &Field) -> bool { |
| 1061 | field.callsite() == self.callsite() |
| 1062 | && self |
| 1063 | .values |
| 1064 | .iter() |
| 1065 | .any(|(key, val)| *key == field && val.is_some()) |
| 1066 | } |
| 1067 | |
| 1068 | /// Returns true if this `ValueSet` contains _no_ values. |
| 1069 | pub fn is_empty(&self) -> bool { |
| 1070 | let my_callsite = self.callsite(); |
| 1071 | self.values |
| 1072 | .iter() |
| 1073 | .all(|(key, val)| val.is_none() || key.callsite() != my_callsite) |
| 1074 | } |
| 1075 | |
| 1076 | pub(crate) fn field_set(&self) -> &FieldSet { |
| 1077 | self.fields |
| 1078 | } |
| 1079 | } |
| 1080 | |
| 1081 | impl<'a> fmt::Debug for ValueSet<'a> { |
| 1082 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1083 | self.values |
| 1084 | .iter() |
| 1085 | .fold(&mut f.debug_struct("ValueSet" ), |dbg, (key, v)| { |
| 1086 | if let Some(val) = v { |
| 1087 | val.record(key, dbg); |
| 1088 | } |
| 1089 | dbg |
| 1090 | }) |
| 1091 | .field(name:"callsite" , &self.callsite()) |
| 1092 | .finish() |
| 1093 | } |
| 1094 | } |
| 1095 | |
| 1096 | impl<'a> fmt::Display for ValueSet<'a> { |
| 1097 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1098 | self.values |
| 1099 | .iter() |
| 1100 | .fold(&mut f.debug_map(), |dbg: &mut DebugMap<'_, '_>, (key: &&Field, v: &Option<&dyn Value>)| { |
| 1101 | if let Some(val: &&'a dyn Value) = v { |
| 1102 | val.record(key, visitor:dbg); |
| 1103 | } |
| 1104 | dbg |
| 1105 | }) |
| 1106 | .finish() |
| 1107 | } |
| 1108 | } |
| 1109 | |
| 1110 | // ===== impl ValidLen ===== |
| 1111 | |
| 1112 | mod private { |
| 1113 | use super::*; |
| 1114 | |
| 1115 | /// Restrictions on `ValueSet` lengths were removed in #2508 but this type remains for backwards compatibility. |
| 1116 | pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {} |
| 1117 | |
| 1118 | impl<'a, const N: usize> ValidLen<'a> for [(&'a Field, Option<&'a (dyn Value + 'a)>); N] {} |
| 1119 | } |
| 1120 | |
| 1121 | #[cfg (test)] |
| 1122 | mod test { |
| 1123 | use super::*; |
| 1124 | use crate::metadata::{Kind, Level, Metadata}; |
| 1125 | use crate::stdlib::{borrow::ToOwned, string::String}; |
| 1126 | |
| 1127 | // Make sure TEST_CALLSITE_* have non-zero size, so they can't be located at the same address. |
| 1128 | struct TestCallsite1(); |
| 1129 | static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1(); |
| 1130 | static TEST_META_1: Metadata<'static> = metadata! { |
| 1131 | name: "field_test1" , |
| 1132 | target: module_path!(), |
| 1133 | level: Level::INFO, |
| 1134 | fields: &["foo" , "bar" , "baz" ], |
| 1135 | callsite: &TEST_CALLSITE_1, |
| 1136 | kind: Kind::SPAN, |
| 1137 | }; |
| 1138 | |
| 1139 | impl crate::callsite::Callsite for TestCallsite1 { |
| 1140 | fn set_interest(&self, _: crate::subscriber::Interest) { |
| 1141 | unimplemented!() |
| 1142 | } |
| 1143 | |
| 1144 | fn metadata(&self) -> &Metadata<'_> { |
| 1145 | &TEST_META_1 |
| 1146 | } |
| 1147 | } |
| 1148 | |
| 1149 | struct TestCallsite2(); |
| 1150 | static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2(); |
| 1151 | static TEST_META_2: Metadata<'static> = metadata! { |
| 1152 | name: "field_test2" , |
| 1153 | target: module_path!(), |
| 1154 | level: Level::INFO, |
| 1155 | fields: &["foo" , "bar" , "baz" ], |
| 1156 | callsite: &TEST_CALLSITE_2, |
| 1157 | kind: Kind::SPAN, |
| 1158 | }; |
| 1159 | |
| 1160 | impl crate::callsite::Callsite for TestCallsite2 { |
| 1161 | fn set_interest(&self, _: crate::subscriber::Interest) { |
| 1162 | unimplemented!() |
| 1163 | } |
| 1164 | |
| 1165 | fn metadata(&self) -> &Metadata<'_> { |
| 1166 | &TEST_META_2 |
| 1167 | } |
| 1168 | } |
| 1169 | |
| 1170 | #[test ] |
| 1171 | fn value_set_with_no_values_is_empty() { |
| 1172 | let fields = TEST_META_1.fields(); |
| 1173 | let values = &[ |
| 1174 | (&fields.field("foo" ).unwrap(), None), |
| 1175 | (&fields.field("bar" ).unwrap(), None), |
| 1176 | (&fields.field("baz" ).unwrap(), None), |
| 1177 | ]; |
| 1178 | let valueset = fields.value_set(values); |
| 1179 | assert!(valueset.is_empty()); |
| 1180 | } |
| 1181 | |
| 1182 | #[test ] |
| 1183 | fn index_of_field_in_fieldset_is_correct() { |
| 1184 | let fields = TEST_META_1.fields(); |
| 1185 | let foo = fields.field("foo" ).unwrap(); |
| 1186 | assert_eq!(foo.index(), 0); |
| 1187 | let bar = fields.field("bar" ).unwrap(); |
| 1188 | assert_eq!(bar.index(), 1); |
| 1189 | let baz = fields.field("baz" ).unwrap(); |
| 1190 | assert_eq!(baz.index(), 2); |
| 1191 | } |
| 1192 | |
| 1193 | #[test ] |
| 1194 | fn empty_value_set_is_empty() { |
| 1195 | let fields = TEST_META_1.fields(); |
| 1196 | let valueset = fields.value_set(&[]); |
| 1197 | assert!(valueset.is_empty()); |
| 1198 | } |
| 1199 | |
| 1200 | #[test ] |
| 1201 | fn value_sets_with_fields_from_other_callsites_are_empty() { |
| 1202 | let fields = TEST_META_1.fields(); |
| 1203 | let values = &[ |
| 1204 | (&fields.field("foo" ).unwrap(), Some(&1 as &dyn Value)), |
| 1205 | (&fields.field("bar" ).unwrap(), Some(&2 as &dyn Value)), |
| 1206 | (&fields.field("baz" ).unwrap(), Some(&3 as &dyn Value)), |
| 1207 | ]; |
| 1208 | let valueset = TEST_META_2.fields().value_set(values); |
| 1209 | assert!(valueset.is_empty()) |
| 1210 | } |
| 1211 | |
| 1212 | #[test ] |
| 1213 | fn sparse_value_sets_are_not_empty() { |
| 1214 | let fields = TEST_META_1.fields(); |
| 1215 | let values = &[ |
| 1216 | (&fields.field("foo" ).unwrap(), None), |
| 1217 | (&fields.field("bar" ).unwrap(), Some(&57 as &dyn Value)), |
| 1218 | (&fields.field("baz" ).unwrap(), None), |
| 1219 | ]; |
| 1220 | let valueset = fields.value_set(values); |
| 1221 | assert!(!valueset.is_empty()); |
| 1222 | } |
| 1223 | |
| 1224 | #[test ] |
| 1225 | fn fields_from_other_callsets_are_skipped() { |
| 1226 | let fields = TEST_META_1.fields(); |
| 1227 | let values = &[ |
| 1228 | (&fields.field("foo" ).unwrap(), None), |
| 1229 | ( |
| 1230 | &TEST_META_2.fields().field("bar" ).unwrap(), |
| 1231 | Some(&57 as &dyn Value), |
| 1232 | ), |
| 1233 | (&fields.field("baz" ).unwrap(), None), |
| 1234 | ]; |
| 1235 | |
| 1236 | struct MyVisitor; |
| 1237 | impl Visit for MyVisitor { |
| 1238 | fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) { |
| 1239 | assert_eq!(field.callsite(), TEST_META_1.callsite()) |
| 1240 | } |
| 1241 | } |
| 1242 | let valueset = fields.value_set(values); |
| 1243 | valueset.record(&mut MyVisitor); |
| 1244 | } |
| 1245 | |
| 1246 | #[test ] |
| 1247 | fn empty_fields_are_skipped() { |
| 1248 | let fields = TEST_META_1.fields(); |
| 1249 | let values = &[ |
| 1250 | (&fields.field("foo" ).unwrap(), Some(&Empty as &dyn Value)), |
| 1251 | (&fields.field("bar" ).unwrap(), Some(&57 as &dyn Value)), |
| 1252 | (&fields.field("baz" ).unwrap(), Some(&Empty as &dyn Value)), |
| 1253 | ]; |
| 1254 | |
| 1255 | struct MyVisitor; |
| 1256 | impl Visit for MyVisitor { |
| 1257 | fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) { |
| 1258 | assert_eq!(field.name(), "bar" ) |
| 1259 | } |
| 1260 | } |
| 1261 | let valueset = fields.value_set(values); |
| 1262 | valueset.record(&mut MyVisitor); |
| 1263 | } |
| 1264 | |
| 1265 | #[test ] |
| 1266 | fn record_debug_fn() { |
| 1267 | let fields = TEST_META_1.fields(); |
| 1268 | let values = &[ |
| 1269 | (&fields.field("foo" ).unwrap(), Some(&1 as &dyn Value)), |
| 1270 | (&fields.field("bar" ).unwrap(), Some(&2 as &dyn Value)), |
| 1271 | (&fields.field("baz" ).unwrap(), Some(&3 as &dyn Value)), |
| 1272 | ]; |
| 1273 | let valueset = fields.value_set(values); |
| 1274 | let mut result = String::new(); |
| 1275 | valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| { |
| 1276 | use crate::stdlib::fmt::Write; |
| 1277 | write!(&mut result, "{:?}" , value).unwrap(); |
| 1278 | }); |
| 1279 | assert_eq!(result, "123" .to_owned()); |
| 1280 | } |
| 1281 | |
| 1282 | #[test ] |
| 1283 | #[cfg (feature = "std" )] |
| 1284 | fn record_error() { |
| 1285 | let fields = TEST_META_1.fields(); |
| 1286 | let err: Box<dyn std::error::Error + Send + Sync + 'static> = |
| 1287 | std::io::Error::new(std::io::ErrorKind::Other, "lol" ).into(); |
| 1288 | let values = &[ |
| 1289 | (&fields.field("foo" ).unwrap(), Some(&err as &dyn Value)), |
| 1290 | (&fields.field("bar" ).unwrap(), Some(&Empty as &dyn Value)), |
| 1291 | (&fields.field("baz" ).unwrap(), Some(&Empty as &dyn Value)), |
| 1292 | ]; |
| 1293 | let valueset = fields.value_set(values); |
| 1294 | let mut result = String::new(); |
| 1295 | valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| { |
| 1296 | use core::fmt::Write; |
| 1297 | write!(&mut result, "{:?}" , value).unwrap(); |
| 1298 | }); |
| 1299 | assert_eq!(result, format!("{}" , err)); |
| 1300 | } |
| 1301 | |
| 1302 | #[test ] |
| 1303 | fn record_bytes() { |
| 1304 | let fields = TEST_META_1.fields(); |
| 1305 | let first = &b"abc" [..]; |
| 1306 | let second: &[u8] = &[192, 255, 238]; |
| 1307 | let values = &[ |
| 1308 | (&fields.field("foo" ).unwrap(), Some(&first as &dyn Value)), |
| 1309 | (&fields.field("bar" ).unwrap(), Some(&" " as &dyn Value)), |
| 1310 | (&fields.field("baz" ).unwrap(), Some(&second as &dyn Value)), |
| 1311 | ]; |
| 1312 | let valueset = fields.value_set(values); |
| 1313 | let mut result = String::new(); |
| 1314 | valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| { |
| 1315 | use core::fmt::Write; |
| 1316 | write!(&mut result, "{:?}" , value).unwrap(); |
| 1317 | }); |
| 1318 | assert_eq!(result, format!("{}" , r#"[61 62 63]" "[c0 ff ee]"# )); |
| 1319 | } |
| 1320 | } |
| 1321 | |