1 | //! `Span` and `Event` key-value data. |
2 | //! |
3 | //! Spans and events may be annotated with key-value data, referred to as known |
4 | //! as _fields_. These fields consist of a mapping from a key (corresponding to |
5 | //! a `&str` but 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 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`, `bool`, and `&str`) or using a `fmt::Display` or |
20 | //! `fmt::Debug` implementation. `Subscriber`s are provided these primitive |
21 | //! 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 | //! [`fmt::Debug`]: std::fmt::Debug |
98 | //! [`fmt::Display`]: std::fmt::Debug |
99 | //! [`valuable`]: https://crates.io/crates/valuable |
100 | //! [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html |
101 | //! [`as_value`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html#tymethod.as_value |
102 | //! [`valuable::Value`]: https://docs.rs/valuable/latest/valuable/enum.Value.html |
103 | //! [`Subscriber`]: crate::Subscriber |
104 | //! [`record_value`]: Visit::record_value |
105 | //! [`record_debug`]: Visit::record_debug |
106 | //! [span]: mod@crate::span |
107 | //! [`Event`]: crate::event::Event |
108 | //! [`Metadata`]: crate::Metadata |
109 | //! [`Attributes`]: crate::span::Attributes |
110 | //! [`Record`]: crate::span::Record |
111 | //! [`new_span`]: crate::Subscriber::new_span |
112 | //! [`record`]: crate::Subscriber::record |
113 | //! [`event`]: crate::Subscriber::event |
114 | pub use tracing_core::field::*; |
115 | |
116 | use crate::Metadata; |
117 | |
118 | /// Trait implemented to allow a type to be used as a field key. |
119 | /// |
120 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
121 | /// <strong>Note</strong>: Although this is implemented for both the |
122 | /// <a href="./struct.Field.html"><code>Field</code></a> type <em>and</em> any |
123 | /// type that can be borrowed as an <code>&str</code>, only <code>Field</code> |
124 | /// allows <em>O</em>(1) access. |
125 | /// Indexing a field with a string results in an iterative search that performs |
126 | /// string comparisons. Thus, if possible, once the key for a field is known, it |
127 | /// should be used whenever possible. |
128 | /// </pre> |
129 | pub trait AsField: crate::sealed::Sealed { |
130 | /// Attempts to convert `&self` into a `Field` with the specified `metadata`. |
131 | /// |
132 | /// If `metadata` defines this field, then the field is returned. Otherwise, |
133 | /// this returns `None`. |
134 | fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field>; |
135 | } |
136 | |
137 | // ===== impl AsField ===== |
138 | |
139 | impl AsField for Field { |
140 | #[inline ] |
141 | fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> { |
142 | if self.callsite() == metadata.callsite() { |
143 | Some(self.clone()) |
144 | } else { |
145 | None |
146 | } |
147 | } |
148 | } |
149 | |
150 | impl<'a> AsField for &'a Field { |
151 | #[inline ] |
152 | fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> { |
153 | if self.callsite() == metadata.callsite() { |
154 | Some((*self).clone()) |
155 | } else { |
156 | None |
157 | } |
158 | } |
159 | } |
160 | |
161 | impl AsField for str { |
162 | #[inline ] |
163 | fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> { |
164 | metadata.fields().field(&self) |
165 | } |
166 | } |
167 | |
168 | impl crate::sealed::Sealed for Field {} |
169 | impl<'a> crate::sealed::Sealed for &'a Field {} |
170 | impl crate::sealed::Sealed for str {} |
171 | |