xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/log-0.4.21/src/kv/mod.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //! Structured logging.
2 //!
3 //! Add the `kv` feature to your `Cargo.toml` to enable
4 //! this module:
5 //!
6 //! ```toml
7 //! [dependencies.log]
8 //! features = ["kv"]
9 //! ```
10 //!
11 //! # Structured logging in `log`
12 //!
13 //! Structured logging enhances traditional text-based log records with user-defined
14 //! attributes. Structured logs can be analyzed using a variety of data processing
15 //! techniques, without needing to find and parse attributes from unstructured text first.
16 //!
17 //! In `log`, user-defined attributes are part of a [`Source`] on the log record.
18 //! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings
19 //! and values are a datum of any type that can be formatted or serialized. Simple types
20 //! like strings, booleans, and numbers are supported, as well as arbitrarily complex
21 //! structures involving nested objects and sequences.
22 //!
23 //! ## Adding key-values to log records
24 //!
25 //! Key-values appear before the message format in the `log!` macros:
26 //!
27 //! ```
28 //! # use log::info;
29 //! info!(a = 1; "Something of interest");
30 //! ```
31 //!
32 //! Key-values support the same shorthand identifer syntax as `format_args`:
33 //!
34 //! ```
35 //! # use log::info;
36 //! let a = 1;
37 //!
38 //! info!(a; "Something of interest");
39 //! ```
40 //!
41 //! Values are capturing using the [`ToValue`] trait by default. To capture a value
42 //! using a different trait implementation, use a modifier after its key. Here's how
43 //! the same example can capture `a` using its `Debug` implementation instead:
44 //!
45 //! ```
46 //! # use log::info;
47 //! info!(a:? = 1; "Something of interest");
48 //! ```
49 //!
50 //! The following capturing modifiers are supported:
51 //!
52 //! - `:?` will capture the value using `Debug`.
53 //! - `:debug` will capture the value using `Debug`.
54 //! - `:%` will capture the value using `Display`.
55 //! - `:display` will capture the value using `Display`.
56 //! - `:err` will capture the value using `std::error::Error` (requires the `kv_std` feature).
57 //! - `:sval` will capture the value using `sval::Value` (requires the `kv_sval` feature).
58 //! - `:serde` will capture the value using `serde::Serialize` (requires the `kv_serde` feature).
59 //!
60 //! ## Working with key-values on log records
61 //!
62 //! Use the [`Record::key_values`](../struct.Record.html#method.key_values) method to access key-values.
63 //!
64 //! Individual values can be pulled from the source by their key:
65 //!
66 //! ```
67 //! # fn main() -> Result<(), log::kv::Error> {
68 //! use log::kv::{Source, Key, Value};
69 //! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
70 //!
71 //! // info!(a = 1; "Something of interest");
72 //!
73 //! let a: Value = record.key_values().get(Key::from("a")).unwrap();
74 //! assert_eq!(1, a.to_i64().unwrap());
75 //! # Ok(())
76 //! # }
77 //! ```
78 //!
79 //! All key-values can also be enumerated using a [`VisitSource`]:
80 //!
81 //! ```
82 //! # fn main() -> Result<(), log::kv::Error> {
83 //! use std::collections::BTreeMap;
84 //!
85 //! use log::kv::{self, Source, Key, Value, VisitSource};
86 //!
87 //! struct Collect<'kvs>(BTreeMap<Key<'kvs>, Value<'kvs>>);
88 //!
89 //! impl<'kvs> VisitSource<'kvs> for Collect<'kvs> {
90 //!     fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
91 //!         self.0.insert(key, value);
92 //!
93 //!         Ok(())
94 //!     }
95 //! }
96 //!
97 //! let mut visitor = Collect(BTreeMap::new());
98 //!
99 //! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build();
100 //! // info!(a = 1, b = 2, c = 3; "Something of interest");
101 //!
102 //! record.key_values().visit(&mut visitor)?;
103 //!
104 //! let collected = visitor.0;
105 //!
106 //! assert_eq!(
107 //!     vec!["a", "b", "c"],
108 //!     collected
109 //!         .keys()
110 //!         .map(|k| k.as_str())
111 //!         .collect::<Vec<_>>(),
112 //! );
113 //! # Ok(())
114 //! # }
115 //! ```
116 //!
117 //! [`Value`]s have methods for conversions to common types:
118 //!
119 //! ```
120 //! # fn main() -> Result<(), log::kv::Error> {
121 //! use log::kv::{Source, Key};
122 //! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
123 //!
124 //! // info!(a = 1; "Something of interest");
125 //!
126 //! let a = record.key_values().get(Key::from("a")).unwrap();
127 //!
128 //! assert_eq!(1, a.to_i64().unwrap());
129 //! # Ok(())
130 //! # }
131 //! ```
132 //!
133 //! Values also have their own [`VisitValue`] type. Value visitors are a lightweight
134 //! API for working with primitives types:
135 //!
136 //! ```
137 //! # fn main() -> Result<(), log::kv::Error> {
138 //! use log::kv::{self, Source, Key, VisitValue};
139 //! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
140 //!
141 //! struct IsNumeric(bool);
142 //!
143 //! impl<'kvs> VisitValue<'kvs> for IsNumeric {
144 //!     fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> {
145 //!         self.0 = false;
146 //!         Ok(())
147 //!     }
148 //!
149 //!     fn visit_u64(&mut self, _value: u64) -> Result<(), kv::Error> {
150 //!         self.0 = true;
151 //!         Ok(())
152 //!     }
153 //!
154 //!     fn visit_i64(&mut self, _value: i64) -> Result<(), kv::Error> {
155 //!         self.0 = true;
156 //!         Ok(())
157 //!     }
158 //!
159 //!     fn visit_u128(&mut self, _value: u128) -> Result<(), kv::Error> {
160 //!         self.0 = true;
161 //!         Ok(())
162 //!     }
163 //!
164 //!     fn visit_i128(&mut self, _value: i128) -> Result<(), kv::Error> {
165 //!         self.0 = true;
166 //!         Ok(())
167 //!     }
168 //!
169 //!     fn visit_f64(&mut self, _value: f64) -> Result<(), kv::Error> {
170 //!         self.0 = true;
171 //!         Ok(())
172 //!     }
173 //! }
174 //!
175 //! // info!(a = 1; "Something of interest");
176 //!
177 //! let a = record.key_values().get(Key::from("a")).unwrap();
178 //!
179 //! let mut visitor = IsNumeric(false);
180 //!
181 //! a.visit(&mut visitor)?;
182 //!
183 //! let is_numeric = visitor.0;
184 //!
185 //! assert!(is_numeric);
186 //! # Ok(())
187 //! # }
188 //! ```
189 //!
190 //! To serialize a value to a format like JSON, you can also use either `serde` or `sval`:
191 //!
192 //! ```
193 //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
194 //! # #[cfg(feature = "serde")]
195 //! # {
196 //! # use log::kv::Key;
197 //! #[derive(serde::Serialize)]
198 //! struct Data {
199 //!     a: i32, b: bool,
200 //!     c: &'static str,
201 //! }
202 //!
203 //! let data = Data { a: 1, b: true, c: "Some data" };
204 //!
205 //! # let source = [("a", log::kv::Value::from_serde(&data))];
206 //! # let record = log::Record::builder().key_values(&source).build();
207 //! // info!(a = data; "Something of interest");
208 //!
209 //! let a = record.key_values().get(Key::from("a")).unwrap();
210 //!
211 //! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?);
212 //! # }
213 //! # Ok(())
214 //! # }
215 //! ```
216 //!
217 //! The choice of serialization framework depends on the needs of the consumer.
218 //! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`.
219 //! Log producers and log consumers don't need to agree on the serialization framework.
220 //! A value can be captured using its `serde::Serialize` implementation and still be serialized
221 //! through `sval` without losing any structure or data.
222 //!
223 //! Values can also always be formatted using the standard `Debug` and `Display`
224 //! traits:
225 //!
226 //! ```
227 //! # use log::kv::Key;
228 //! # #[derive(Debug)]
229 //! struct Data {
230 //!     a: i32,
231 //!     b: bool,
232 //!     c: &'static str,
233 //! }
234 //!
235 //! let data = Data { a: 1, b: true, c: "Some data" };
236 //!
237 //! # let source = [("a", log::kv::Value::from_debug(&data))];
238 //! # let record = log::Record::builder().key_values(&source).build();
239 //! // info!(a = data; "Something of interest");
240 //!
241 //! let a = record.key_values().get(Key::from("a")).unwrap();
242 //!
243 //! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}"));
244 //! ```
245 
246 mod error;
247 mod key;
248 
249 #[cfg(not(feature = "kv_unstable"))]
250 mod source;
251 #[cfg(not(feature = "kv_unstable"))]
252 mod value;
253 
254 pub use self::error::Error;
255 pub use self::key::{Key, ToKey};
256 pub use self::source::{Source, VisitSource};
257 pub use self::value::{ToValue, Value, VisitValue};
258 
259 #[cfg(feature = "kv_unstable")]
260 pub mod source;
261 #[cfg(feature = "kv_unstable")]
262 pub mod value;
263 
264 #[cfg(feature = "kv_unstable")]
265 pub use self::source::Visitor;
266