diff --git a/src/fmt/builder.rs b/src/fmt/builder.rs index bafc2a0..bf62073 100644 --- a/src/fmt/builder.rs +++ b/src/fmt/builder.rs @@ -15,6 +15,18 @@ use tracing_subscriber::{ Registry, }; +use super::names::{ + CURRENT_SPAN, + FIELDS, + FILENAME, + LEVEL, + LINE_NUMBER, + SPAN_LIST, + TARGET, + THREAD_ID, + THREAD_NAME, + TIMESTAMP, +}; use crate::layer::JsonLayer; /// Configures and constructs `Subscriber`s. @@ -142,19 +154,42 @@ where let mut layer = JsonLayer::::new(self.make_writer); if self.display_timestamp { - layer.with_timer(self.timer); + layer.with_timer(TIMESTAMP, self.timer); + } + + if self.display_level { + layer.with_level(LEVEL); + } + + if self.display_target { + layer.with_target(TARGET); + } + + if self.display_filename { + layer.with_file(FILENAME); + } + + if self.display_line_number { + layer.with_line_number(LINE_NUMBER); } - layer - .with_level(self.display_level) - .flatten_event(self.flatten_event) - .with_target(self.display_target) - .with_file(self.display_filename) - .with_line_number(self.display_line_number) - .with_current_span(self.display_current_span) - .with_span_list(self.display_span_list) - .with_thread_names(self.display_thread_name) - .with_thread_ids(self.display_thread_id); + if self.display_thread_name { + layer.with_thread_names(THREAD_NAME); + } + + if self.display_thread_id { + layer.with_thread_ids(THREAD_ID); + } + + layer.with_event(FIELDS, self.flatten_event); + + if self.display_current_span { + layer.with_current_span(CURRENT_SPAN); + } + + if self.display_span_list { + layer.with_span_list(SPAN_LIST); + } (layer, self.filter) } diff --git a/src/fmt/layer.rs b/src/fmt/layer.rs index 28e0abd..745120f 100644 --- a/src/fmt/layer.rs +++ b/src/fmt/layer.rs @@ -12,6 +12,18 @@ use tracing_subscriber::{ Registry, }; +use super::names::{ + CURRENT_SPAN, + FIELDS, + FILENAME, + LEVEL, + LINE_NUMBER, + SPAN_LIST, + TARGET, + THREAD_ID, + THREAD_NAME, + TIMESTAMP, +}; use crate::layer::JsonLayer; /// A [`Layer`] that logs JSON formatted representations of `tracing` events. @@ -60,12 +72,12 @@ impl LookupSpan<'lookup>> Default for Layer { inner // If we do not call this, fields are not printed at all. - .flatten_event(false) - .with_timer(SystemTime) - .with_target(true) - .with_level(true) - .with_current_span(true) - .with_span_list(true); + .with_event(FIELDS, false) + .with_timer(TIMESTAMP, SystemTime) + .with_target(TARGET) + .with_level(LEVEL) + .with_current_span(CURRENT_SPAN) + .with_span_list(SPAN_LIST); Self { inner } } @@ -329,13 +341,17 @@ where /// Sets the JSON subscriber being built to flatten event metadata. pub fn flatten_event(mut self, flatten_event: bool) -> Self { - self.inner.flatten_event(flatten_event); + self.inner.with_event(FIELDS, flatten_event); self } /// Sets whether or not the formatter will include the current span in formatted events. pub fn with_current_span(mut self, display_current_span: bool) -> Self { - self.inner.with_current_span(display_current_span); + if display_current_span { + self.inner.with_current_span(CURRENT_SPAN); + } else { + self.inner.remove_field(CURRENT_SPAN); + } self } @@ -344,7 +360,11 @@ where /// /// This overrides any previous calls to [`with_flat_span_list`](Self::with_flat_span_list). pub fn with_span_list(mut self, display_span_list: bool) -> Self { - self.inner.with_span_list(display_span_list); + if display_span_list { + self.inner.with_span_list(SPAN_LIST); + } else { + self.inner.remove_field(SPAN_LIST); + } self } @@ -355,9 +375,9 @@ where /// This overrides any previous calls to [`with_span_list`](Self::with_span_list). pub fn with_flat_span_list(mut self, flatten_span_list: bool) -> Self { if flatten_span_list { - self.inner.flatten_span_list(); + self.inner.flatten_span_list(SPAN_LIST); } else { - self.inner.with_span_list(false); + self.inner.remove_field(SPAN_LIST); } self } @@ -377,19 +397,23 @@ where /// [`LocalTime`]: tracing_subscriber::fmt::time::LocalTime /// [`time` crate]: https://docs.rs/time/0.3 pub fn with_timer(mut self, timer: T) -> Self { - self.inner.with_timer(timer); + self.inner.with_timer(TIMESTAMP, timer); self } /// Do not emit timestamps with log messages. pub fn without_time(mut self) -> Self { - self.inner.without_time(); + self.inner.remove_field(TIMESTAMP); self } /// Sets whether or not an event's target is displayed. pub fn with_target(mut self, display_target: bool) -> Self { - self.inner.with_target(display_target); + if display_target { + self.inner.with_target(TARGET); + } else { + self.inner.remove_field(TARGET) + } self } @@ -399,7 +423,11 @@ where /// /// [file]: tracing_core::Metadata::file pub fn with_file(mut self, display_filename: bool) -> Self { - self.inner.with_file(display_filename); + if display_filename { + self.inner.with_file(FILENAME); + } else { + self.inner.remove_field(FILENAME); + } self } @@ -408,13 +436,21 @@ where /// /// [line]: tracing_core::Metadata::line pub fn with_line_number(mut self, display_line_number: bool) -> Self { - self.inner.with_line_number(display_line_number); + if display_line_number { + self.inner.with_line_number(LINE_NUMBER); + } else { + self.inner.remove_field(LINE_NUMBER); + } self } /// Sets whether or not an event's level is displayed. pub fn with_level(mut self, display_level: bool) -> Self { - self.inner.with_level(display_level); + if display_level { + self.inner.with_level(LEVEL); + } else { + self.inner.remove_field(LEVEL); + } self } @@ -423,7 +459,11 @@ where /// /// [name]: std::thread#naming-threads pub fn with_thread_names(mut self, display_thread_name: bool) -> Self { - self.inner.with_thread_names(display_thread_name); + if display_thread_name { + self.inner.with_thread_names(THREAD_NAME); + } else { + self.inner.remove_field(THREAD_NAME); + } self } @@ -432,7 +472,12 @@ where /// /// [thread ID]: std::thread::ThreadId pub fn with_thread_ids(mut self, display_thread_id: bool) -> Self { - self.inner.with_thread_ids(display_thread_id); + if display_thread_id { + self.inner.with_thread_ids(THREAD_ID); + } else { + self.inner.remove_field(THREAD_ID); + } + self } diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 5820eca..85483bf 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -10,6 +10,7 @@ use tracing_subscriber::{registry::LookupSpan, util::SubscriberInitExt}; mod builder; mod layer; +mod names; /// Returns a new [`SubscriberBuilder`] for configuring a json [formatting subscriber]. /// diff --git a/src/fmt/names.rs b/src/fmt/names.rs new file mode 100644 index 0000000..5f67390 --- /dev/null +++ b/src/fmt/names.rs @@ -0,0 +1,10 @@ +pub(super) const CURRENT_SPAN: &str = "span"; +pub(super) const FIELDS: &str = "fields"; +pub(super) const FILENAME: &str = "filename"; +pub(super) const LEVEL: &str = "level"; +pub(super) const LINE_NUMBER: &str = "line_number"; +pub(super) const SPAN_LIST: &str = "spans"; +pub(super) const TARGET: &str = "target"; +pub(super) const THREAD_ID: &str = "threadId"; +pub(super) const THREAD_NAME: &str = "threadName"; +pub(super) const TIMESTAMP: &str = "timestamp"; diff --git a/src/layer/mod.rs b/src/layer/mod.rs index d5072fa..a0119c8 100644 --- a/src/layer/mod.rs +++ b/src/layer/mod.rs @@ -379,11 +379,7 @@ where /// registry().with(layer); /// # fn get_hostname() -> &'static str { "localhost" } /// ``` - pub fn add_static_field( - &mut self, - key: impl Into>, - value: serde_json::Value, - ) { + pub fn add_static_field(&mut self, key: impl Into, value: serde_json::Value) { self.schema.insert( SchemaKey::from(key.into()), JsonValue::Serde(DynamicJsonValue { @@ -411,7 +407,7 @@ where /// /// registry().with(layer); /// ``` - pub fn remove_field(&mut self, key: impl Into>) { + pub fn remove_field(&mut self, key: impl Into) { self.schema.remove(&SchemaKey::from(key.into())); } @@ -458,10 +454,7 @@ where /// registry().with(foo_layer).with(layer); /// # } /// ``` - pub fn serialize_extension( - &mut self, - key: impl Into>, - ) { + pub fn serialize_extension(&mut self, key: impl Into) { self.add_from_extension_ref(key, |extension: &Ext| Some(extension)) } @@ -511,11 +504,8 @@ where /// registry().with(foo_layer).with(layer); /// # } /// ``` - pub fn add_from_extension_ref( - &mut self, - key: impl Into>, - mapper: Fun, - ) where + pub fn add_from_extension_ref(&mut self, key: impl Into, mapper: Fun) + where Ext: 'static, for<'a> Fun: Fn(&'a Ext) -> Option<&'a Res> + Send + Sync + 'a, Res: serde::Serialize, @@ -580,11 +570,8 @@ where /// registry().with(foo_layer).with(layer); /// # } /// ``` - pub fn add_from_extension( - &mut self, - key: impl Into>, - mapper: Fun, - ) where + pub fn add_from_extension(&mut self, key: impl Into, mapper: Fun) + where Ext: 'static, for<'a> Fun: Fn(&'a Ext) -> Option + Send + Sync + 'a, Res: serde::Serialize, @@ -608,12 +595,12 @@ where /// If set to `true`, it is the user's responsibility to make sure that the field names will not /// clash with other defined fields. If they clash, invalid JSON with multiple fields with the /// same key may be generated. - pub fn flatten_event(&mut self, flatten_event: bool) -> &mut Self { + pub fn with_event(&mut self, key: impl Into, flatten: bool) -> &mut Self { self.schema.insert( - SchemaKey::from("fields"), + SchemaKey::from(key.into()), JsonValue::DynamicFromEvent(Box::new(move |event| { Some(DynamicJsonValue { - flatten: flatten_event, + flatten, value: serde_json::to_value(event.field_map()).ok()?, }) })), @@ -623,44 +610,36 @@ where /// Sets whether or not the log line will include the current span in formatted events. If set /// to true, it will be printed with the key `span`. - pub fn with_current_span(&mut self, display_current_span: bool) -> &mut Self { - if display_current_span { - self.schema.insert( - SchemaKey::from("span"), - JsonValue::DynamicCachedFromSpan(Box::new(move |span| { - span.extensions() - .get::() - .map(|fields| Cached::Raw(fields.serialized.as_ref().unwrap().clone())) - })), - ); - } else { - self.schema.remove(&SchemaKey::from("span")); - } + pub fn with_current_span(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicCachedFromSpan(Box::new(move |span| { + span.extensions() + .get::() + .map(|fields| Cached::Raw(fields.serialized.as_ref().unwrap().clone())) + })), + ); self } /// Sets whether or not the formatter will include a list (from root to leaf) of all currently /// entered spans in formatted events. If set to true, it will be printed with the key `spans`. - pub fn with_span_list(&mut self, display_span_list: bool) -> &mut Self { - if display_span_list { - self.schema.insert( - SchemaKey::from("spans"), - JsonValue::DynamicCachedFromSpan(Box::new(|span| { - Some(Cached::Array( - span.scope() - .from_root() - .flat_map(|span| { - span.extensions() - .get::() - .map(|fields| fields.serialized.as_ref().unwrap().clone()) - }) - .collect::>(), - )) - })), - ); - } else { - self.schema.remove(&SchemaKey::from("spans")); - } + pub fn with_span_list(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicCachedFromSpan(Box::new(|span| { + Some(Cached::Array( + span.scope() + .from_root() + .flat_map(|span| { + span.extensions() + .get::() + .map(|fields| fields.serialized.as_ref().unwrap().clone()) + }) + .collect::>(), + )) + })), + ); self } @@ -669,9 +648,9 @@ where /// values of spans that are closer to the root spans. /// /// This overrides any previous calls to [`with_span_list`](Self::with_span_list). - pub(crate) fn flatten_span_list(&mut self) -> &mut Self { + pub(crate) fn flatten_span_list(&mut self, key: impl Into) -> &mut Self { self.schema.insert( - SchemaKey::from("spans"), + SchemaKey::from(key.into()), JsonValue::DynamicFromSpan(Box::new(|span| { let fields = span.scope() @@ -705,9 +684,13 @@ where /// /// [`timer`]: tracing_subscriber::fmt::time::FormatTime /// [`time` module]: mod@tracing_subscriber::fmt::time - pub fn with_timer(&mut self, timer: T) -> &mut Self { + pub fn with_timer( + &mut self, + key: impl Into, + timer: T, + ) -> &mut Self { self.schema.insert( - SchemaKey::from("timestamp"), + SchemaKey::from(key.into()), JsonValue::DynamicFromEvent(Box::new(move |_| { let mut timestamp = String::with_capacity(32); timer.format_time(&mut Writer::new(&mut timestamp)).ok()?; @@ -721,26 +704,16 @@ where self } - /// Clears the `timestamp` fields. - pub fn without_time(&mut self) -> &mut Self { - self.schema.remove(&SchemaKey::from("timestamp")); - self - } - /// Sets whether or not an event's target is displayed. It will use the `target` key if so. - pub fn with_target(&mut self, display_target: bool) -> &mut Self { - if display_target { - self.schema.insert( - SchemaKey::from("target"), - JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - writer.write_str("\"")?; - writer.write_str(event.metadata().target())?; - writer.write_str("\"") - })), - ); - } else { - self.schema.remove(&SchemaKey::from("target")); - } + pub fn with_target(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { + writer.write_str("\"")?; + writer.write_str(event.metadata().target())?; + writer.write_str("\"") + })), + ); self } @@ -749,25 +722,21 @@ where /// `file` key if so. /// /// [file]: tracing_core::Metadata::file - pub fn with_file(&mut self, display_filename: bool) -> &mut Self { - if display_filename { - self.schema.insert( - SchemaKey::from("filename"), - JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - event - .metadata() - .file() - .map(|file| { - writer.write_str("\"")?; - writer.write_str(file)?; - writer.write_str("\"") - }) - .unwrap_or(Ok(())) - })), - ); - } else { - self.schema.remove(&SchemaKey::from("filename")); - } + pub fn with_file(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { + event + .metadata() + .file() + .map(|file| { + writer.write_str("\"")?; + writer.write_str(file)?; + writer.write_str("\"") + }) + .unwrap_or(Ok(())) + })), + ); self } @@ -775,38 +744,30 @@ where /// `line_number` key if so. /// /// [line]: tracing_core::Metadata::line - pub fn with_line_number(&mut self, display_line_number: bool) -> &mut Self { - if display_line_number { - self.schema.insert( - SchemaKey::from("line_number"), - JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - event - .metadata() - .line() - .map(|file| write!(writer, "{}", file)) - .unwrap_or(Ok(())) - })), - ); - } else { - self.schema.remove(&SchemaKey::from("line_number")); - } + pub fn with_line_number(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { + event + .metadata() + .line() + .map(|file| write!(writer, "{}", file)) + .unwrap_or(Ok(())) + })), + ); self } /// Sets whether or not an event's level is displayed. It will use the `level` key if so. - pub fn with_level(&mut self, display_level: bool) -> &mut Self { - if display_level { - self.schema.insert( - SchemaKey::from("level"), - JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - writer.write_str("\"")?; - writer.write_str(event.metadata().level().as_str())?; - writer.write_str("\"") - })), - ); - } else { - self.schema.remove(&SchemaKey::from("level")); - } + pub fn with_level(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { + writer.write_str("\"")?; + writer.write_str(event.metadata().level().as_str())?; + writer.write_str("\"") + })), + ); self } @@ -814,24 +775,20 @@ where /// will use the `threadName` key if so. /// /// [name]: std::thread#naming-threads - pub fn with_thread_names(&mut self, display_thread_name: bool) -> &mut Self { - if display_thread_name { - self.schema.insert( - SchemaKey::from("threadName"), - JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { - std::thread::current() - .name() - .map(|name| { - writer.write_str("\"")?; - writer.write_str(name)?; - writer.write_str("\"") - }) - .unwrap_or(Ok(())) - })), - ); - } else { - self.schema.remove(&SchemaKey::from("threadName")); - } + pub fn with_thread_names(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { + std::thread::current() + .name() + .map(|name| { + writer.write_str("\"")?; + writer.write_str(name)?; + writer.write_str("\"") + }) + .unwrap_or(Ok(())) + })), + ); self } @@ -839,19 +796,16 @@ where /// events. It will use the `threadId` key if so. /// /// [thread ID]: std::thread::ThreadId - pub fn with_thread_ids(&mut self, display_thread_id: bool) -> &mut Self { - if display_thread_id { - self.schema.insert( - SchemaKey::from("threadId"), - JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { - writer.write_str("\"")?; - write!(writer, "{:?}", std::thread::current().id())?; - writer.write_str("\"") - })), - ); - } else { - self.schema.remove(&SchemaKey::from("threadId")); - } + pub fn with_thread_ids(&mut self, key: impl Into) -> &mut Self { + self.schema.insert( + SchemaKey::from(key.into()), + JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { + writer.write_str("\"")?; + write!(writer, "{:?}", std::thread::current().id())?; + writer.write_str("\"") + })), + ); + self } @@ -944,6 +898,7 @@ mod tests { let mut layer = JsonLayer::stdout(); layer.add_static_field("static", json!({"lorem": "ipsum", "answer": 42})); layer.add_static_field(String::from("zero"), json!(0)); + layer.add_static_field(String::from("one").as_str(), json!(1)); layer.add_static_field("nonExistent", json!(1)); layer.remove_field("nonExistent"); @@ -953,6 +908,7 @@ mod tests { "answer": 42, }, "zero": 0, + "one": 1, }); test_json(expected, layer, || {