diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/tracing-subscriber/src/fmt/format/json.rs (renamed from vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs) | 175 |
1 files changed, 155 insertions, 20 deletions
diff --git a/vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs b/vendor/tracing-subscriber/src/fmt/format/json.rs index cc86f03c7..c2f4d3755 100644 --- a/vendor/tracing-subscriber-0.3.3/src/fmt/format/json.rs +++ b/vendor/tracing-subscriber/src/fmt/format/json.rs @@ -23,25 +23,42 @@ use tracing_serde::AsSerde; #[cfg(feature = "tracing-log")] use tracing_log::NormalizeEvent; -/// Marker for `Format` that indicates that the verbose JSON log format should be used. +/// Marker for [`Format`] that indicates that the newline-delimited JSON log +/// format should be used. /// -/// The full format includes fields from all entered spans. +/// This formatter is intended for production use with systems where structured +/// logs are consumed as JSON by analysis and viewing tools. The JSON output is +/// not optimized for human readability; instead, it should be pretty-printed +/// using external JSON tools such as `jq`, or using a JSON log viewer. /// /// # Example Output /// -/// ```json -/// { -/// "timestamp":"Feb 20 11:28:15.096", -/// "level":"INFO", -/// "fields":{"message":"some message","key":"value"} -/// "target":"mycrate", -/// "span":{name":"leaf"}, -/// "spans":[{"name":"root"},{"name":"leaf"}], -/// } -/// ``` +/// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt-json +/// <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s +/// <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-json` +/// {"timestamp":"2022-02-15T18:47:10.821315Z","level":"INFO","fields":{"message":"preparing to shave yaks","number_of_yaks":3},"target":"fmt_json"} +/// {"timestamp":"2022-02-15T18:47:10.821422Z","level":"INFO","fields":{"message":"shaving yaks"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821495Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821546Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821598Z","level":"DEBUG","fields":{"yak":1,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821637Z","level":"TRACE","fields":{"yaks_shaved":1},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821684Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821727Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821773Z","level":"DEBUG","fields":{"yak":2,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821806Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.821909Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.821956Z","level":"WARN","fields":{"message":"could not locate yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]} +/// {"timestamp":"2022-02-15T18:47:10.822006Z","level":"DEBUG","fields":{"yak":3,"shaved":false},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822041Z","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822079Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]} +/// {"timestamp":"2022-02-15T18:47:10.822117Z","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"} +/// </pre> /// /// # Options /// +/// This formatter exposes additional options to configure the structure of the +/// output JSON objects: +/// /// - [`Json::flatten_event`] can be used to enable flattening event fields into /// the root /// - [`Json::with_current_span`] can be used to control logging of the current @@ -52,9 +69,23 @@ use tracing_log::NormalizeEvent; /// By default, event fields are not flattened, and both current span and span /// list are logged. /// -/// [`Json::flatten_event`]: #method.flatten_event -/// [`Json::with_current_span`]: #method.with_current_span -/// [`Json::with_span_list`]: #method.with_span_list +/// # Valuable Support +/// +/// Experimental support is available for using the [`valuable`] crate to record +/// user-defined values as structured JSON. When the ["valuable" unstable +/// feature][unstable] is enabled, types implementing [`valuable::Valuable`] will +/// be recorded as structured JSON, rather than +/// using their [`std::fmt::Debug`] implementations. +/// +/// **Note**: This is an experimental feature. [Unstable features][unstable] +/// must be enabled in order to use `valuable` support. +/// +/// [`Json::flatten_event`]: Json::flatten_event() +/// [`Json::with_current_span`]: Json::with_current_span() +/// [`Json::with_span_list`]: Json::with_span_list() +/// [`valuable`]: https://crates.io/crates/valuable +/// [unstable]: crate#unstable-features +/// [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Json { pub(crate) flatten_event: bool, @@ -243,6 +274,18 @@ where serializer.serialize_entry("target", meta.target())?; } + if self.display_filename { + if let Some(filename) = meta.file() { + serializer.serialize_entry("filename", filename)?; + } + } + + if self.display_line_number { + if let Some(line_number) = meta.line() { + serializer.serialize_entry("line_number", &line_number)?; + } + } + if self.format.display_current_span { if let Some(ref span) = current_span { serializer @@ -298,7 +341,6 @@ impl Default for Json { /// The JSON [`FormatFields`] implementation. /// -/// [`FormatFields`]: trait.FormatFields.html #[derive(Debug)] pub struct JsonFields { // reserve the ability to add fields to this without causing a breaking @@ -309,7 +351,6 @@ pub struct JsonFields { impl JsonFields { /// Returns a new JSON [`FormatFields`] implementation. /// - /// [`FormatFields`]: trait.FormatFields.html pub fn new() -> Self { Self { _private: () } } @@ -378,9 +419,8 @@ impl<'a> FormatFields<'a> for JsonFields { /// The [visitor] produced by [`JsonFields`]'s [`MakeVisitor`] implementation. /// -/// [visitor]: ../../field/trait.Visit.html -/// [`JsonFields`]: struct.JsonFields.html -/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html +/// [visitor]: crate::field::Visit +/// [`MakeVisitor`]: crate::field::MakeVisitor pub struct JsonVisitor<'a> { values: BTreeMap<&'a str, serde_json::Value>, writer: &'a mut dyn Write, @@ -435,6 +475,26 @@ impl<'a> crate::field::VisitOutput<fmt::Result> for JsonVisitor<'a> { } impl<'a> field::Visit for JsonVisitor<'a> { + #[cfg(all(tracing_unstable, feature = "valuable"))] + fn record_value(&mut self, field: &Field, value: valuable_crate::Value<'_>) { + let value = match serde_json::to_value(valuable_serde::Serializable::new(value)) { + Ok(value) => value, + Err(_e) => { + #[cfg(debug_assertions)] + unreachable!( + "`valuable::Valuable` implementations should always serialize \ + successfully, but an error occurred: {}", + _e, + ); + + #[cfg(not(debug_assertions))] + return; + } + }; + + self.values.insert(field.name(), value); + } + /// Visit a double precision floating point value. fn record_f64(&mut self, field: &Field, value: f64) { self.values @@ -488,6 +548,7 @@ mod test { use tracing::{self, subscriber::with_default}; use std::fmt; + use std::path::Path; struct MockTime; impl FormatTime for MockTime { @@ -516,6 +577,50 @@ mod test { } #[test] + fn json_filename() { + let current_path = Path::new("tracing-subscriber") + .join("src") + .join("fmt") + .join("format") + .join("json.rs") + .to_str() + .expect("path must be valid unicode") + // escape windows backslashes + .replace('\\', "\\\\"); + let expected = + &format!("{}{}{}", + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"filename\":\"", + current_path, + "\",\"fields\":{\"message\":\"some json test\"}}\n"); + let subscriber = subscriber() + .flatten_event(false) + .with_current_span(true) + .with_file(true) + .with_span_list(true); + test_json(expected, subscriber, || { + let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let _guard = span.enter(); + tracing::info!("some json test"); + }); + } + + #[test] + fn json_line_number() { + let expected = + "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"line_number\":42,\"fields\":{\"message\":\"some json test\"}}\n"; + let subscriber = subscriber() + .flatten_event(false) + .with_current_span(true) + .with_line_number(true) + .with_span_list(true); + test_json_with_line_number(expected, subscriber, || { + let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); + let _guard = span.enter(); + tracing::info!("some json test"); + }); + } + + #[test] fn json_flattened_event() { let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"message\":\"some json test\"}\n"; @@ -747,4 +852,34 @@ mod test { serde_json::from_str(actual).unwrap() ); } + + fn test_json_with_line_number<T>( + expected: &str, + builder: crate::fmt::SubscriberBuilder<JsonFields, Format<Json>>, + producer: impl FnOnce() -> T, + ) { + let make_writer = MockMakeWriter::default(); + let subscriber = builder + .with_writer(make_writer.clone()) + .with_timer(MockTime) + .finish(); + + with_default(subscriber, producer); + + let buf = make_writer.buf(); + let actual = std::str::from_utf8(&buf[..]).unwrap(); + let mut expected = + serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected) + .unwrap(); + let expect_line_number = expected.remove("line_number").is_some(); + let mut actual: std::collections::HashMap<&str, serde_json::Value> = + serde_json::from_str(actual).unwrap(); + let line_number = actual.remove("line_number"); + if expect_line_number { + assert_eq!(line_number.map(|x| x.is_number()), Some(true)); + } else { + assert!(line_number.is_none()); + } + assert_eq!(actual, expected); + } } |