diff --git a/Cargo.toml b/Cargo.toml index ab49884..ce023b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "tracing-glog" version = "0.4.0" edition = "2021" +rust-version = "1.58" description = "a glog-inspired formatter for tracing-subscriber" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/src/format.rs b/src/format.rs index a7f6735..cdab0af 100644 --- a/src/format.rs +++ b/src/format.rs @@ -6,24 +6,52 @@ use tracing_subscriber::fmt::{format::Writer, time::FormatTime}; use tracing_subscriber::fmt::time::{ChronoLocal, ChronoUtc}; +pub struct FormatLevelChars { + pub trace: &'static str, + pub debug: &'static str, + pub info: &'static str, + pub warn: &'static str, + pub error: &'static str, +} + +impl FormatLevelChars { + pub const fn const_default() -> FormatLevelChars { + FormatLevelChars { + trace: "T", + debug: "D", + info: "I", + warn: "W", + error: "E", + } + } +} + +impl Default for FormatLevelChars { + fn default() -> FormatLevelChars { + FormatLevelChars::const_default() + } +} + +pub(crate) const DEFAULT_FORMAT_LEVEL_CHARS: FormatLevelChars = FormatLevelChars::const_default(); + pub(crate) struct FmtLevel { pub level: Level, + pub chars: &'static FormatLevelChars, #[cfg(feature = "ansi")] pub ansi: bool, } impl FmtLevel { - const TRACE_STR: &'static str = "T"; - const DEBUG_STR: &'static str = "D"; - const INFO_STR: &'static str = "I"; - const WARN_STR: &'static str = "W"; - const ERROR_STR: &'static str = "E"; - - pub(crate) fn format_level(level: Level, ansi: bool) -> FmtLevel { + pub(crate) fn format_level( + level: Level, + chars: &'static FormatLevelChars, + ansi: bool, + ) -> FmtLevel { #[cfg(not(feature = "ansi"))] let _ = ansi; FmtLevel { level, + chars, #[cfg(feature = "ansi")] ansi, } @@ -32,22 +60,23 @@ impl FmtLevel { impl fmt::Display for FmtLevel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let chars = self.chars; #[cfg(feature = "ansi")] if self.ansi { return match self.level { - Level::TRACE => write!(f, "{}", Color::Purple.paint(Self::TRACE_STR)), - Level::DEBUG => write!(f, "{}", Color::Blue.paint(Self::DEBUG_STR)), - Level::INFO => write!(f, "{}", Color::Green.paint(Self::INFO_STR)), - Level::WARN => write!(f, "{}", Color::Yellow.paint(Self::WARN_STR)), - Level::ERROR => write!(f, "{}", Color::Red.paint(Self::ERROR_STR)), + Level::TRACE => write!(f, "{}", Color::Purple.paint(chars.trace)), + Level::DEBUG => write!(f, "{}", Color::Blue.paint(chars.debug)), + Level::INFO => write!(f, "{}", Color::Green.paint(chars.info)), + Level::WARN => write!(f, "{}", Color::Yellow.paint(chars.warn)), + Level::ERROR => write!(f, "{}", Color::Red.paint(chars.error)), }; } match self.level { - Level::TRACE => f.pad(Self::TRACE_STR), - Level::DEBUG => f.pad(Self::DEBUG_STR), - Level::INFO => f.pad(Self::INFO_STR), - Level::WARN => f.pad(Self::WARN_STR), - Level::ERROR => f.pad(Self::ERROR_STR), + Level::TRACE => f.pad(chars.trace), + Level::DEBUG => f.pad(chars.debug), + Level::INFO => f.pad(chars.info), + Level::WARN => f.pad(chars.warn), + Level::ERROR => f.pad(chars.error), } } } @@ -139,7 +168,7 @@ impl<'a> fmt::Display for FormatProcessData<'a> { let target = self.metadata.target(); let file = self.metadata.file().unwrap_or(""); let line = match self.metadata.line() { - Some(line) => format!("{}", line), + Some(line) => format!("{line}"), None => String::new(), }; // write the always unstyled PID @@ -152,15 +181,15 @@ impl<'a> fmt::Display for FormatProcessData<'a> { write!(f, "{}", style.prefix())?; if let Some(name) = thread_name { if self.with_thread_names { - write!(f, " {}", name)? + write!(f, " {name}")? } } if self.with_target { - write!(f, " [{}]", target)?; + write!(f, " [{target}]")?; } - write!(f, " {file}:{line}", file = file, line = line)?; + write!(f, " {file}:{line}")?; // end bolding write!(f, "{}", style.suffix())?; @@ -169,15 +198,15 @@ impl<'a> fmt::Display for FormatProcessData<'a> { } if let Some(name) = thread_name { if self.with_thread_names { - write!(f, " {}", name)? + write!(f, " {name}")? } } if self.with_target { - write!(f, " [{}]", target)?; + write!(f, " [{target}]")?; } - write!(f, " {file}:{line}", file = file, line = line)?; + write!(f, " {file}:{line}")?; Ok(()) } } @@ -236,9 +265,9 @@ impl<'a> fmt::Display for FormatSpanFields<'a> { } if let Some(fields) = self.fields { if self.print_span_names { - write!(f, "{{{}}}", fields)?; + write!(f, "{{{fields}}}")?; } else { - write!(f, "{}", fields)?; + write!(f, "{fields}")?; } }; diff --git a/src/lib.rs b/src/lib.rs index cefd889..171319e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,7 +128,7 @@ mod nu_ansi_term { use crate::nu_ansi_term::Style; use format::FmtLevel; -pub use format::{LocalTime, UtcTime}; +pub use format::{FormatLevelChars, LocalTime, UtcTime}; use std::fmt; use tracing::{ field::{Field, Visit}, @@ -151,6 +151,7 @@ use crate::format::{FormatProcessData, FormatSpanFields}; /// [glog]: https://github.com/google/glog pub struct Glog { timer: T, + level_chars: &'static FormatLevelChars, with_span_context: bool, with_thread_names: bool, with_target: bool, @@ -170,6 +171,7 @@ impl Glog { { Glog { timer, + level_chars: self.level_chars, with_thread_names: self.with_thread_names, with_target: self.with_target, with_span_context: self.with_span_context, @@ -239,12 +241,22 @@ impl Glog { ..self } } + + /// Sets the characters to use to indicate the level for each event. + /// Defaults to the initial character of the level. + pub fn with_format_level_chars(self, level_chars: &'static FormatLevelChars) -> Glog { + Glog { + level_chars, + ..self + } + } } impl Default for Glog { fn default() -> Self { Glog { timer: UtcTime::default(), + level_chars: &format::DEFAULT_FORMAT_LEVEL_CHARS, with_thread_names: false, with_target: false, with_span_context: true, @@ -268,8 +280,8 @@ where let level = *event.metadata().level(); // Convert log level to a single character representation.) - let level = FmtLevel::format_level(level, writer.has_ansi_escapes()); - write!(writer, "{}", level)?; + let level = FmtLevel::format_level(level, self.level_chars, writer.has_ansi_escapes()); + write!(writer, "{level}")?; // write the timestamp: self.timer.format_time(&mut writer)?; @@ -295,7 +307,7 @@ where #[cfg(feature = "ansi")] ansi: writer.has_ansi_escapes(), }; - write!(writer, "{}] ", data)?; + write!(writer, "{data}] ")?; if self.with_span_context { // now, we're printing the span context into brackets of `[]`, which glog parsers ignore. @@ -333,7 +345,7 @@ where writer.has_ansi_escapes(), self.with_span_names, ); - write!(writer, "{}", fields)?; + write!(writer, "{fields}")?; } drop(ext); @@ -443,7 +455,7 @@ impl<'a> GlogVisitor<'a> { } else { ", " }; - self.result = write!(self.writer, "{}{:?}", padding, value); + self.result = write!(self.writer, "{padding}{value:?}"); } fn write_field(&mut self, name: &str, value: &dyn fmt::Debug) { @@ -483,11 +495,11 @@ impl<'a> Visit for GlogVisitor<'a> { } if field.name() == "message" { - self.record_debug(field, &format_args!("{}", value)) + self.record_debug(field, &format_args!("{value}")) } else if self.config.should_quote_strings { self.record_debug(field, &value) } else { - self.record_debug(field, &format_args!("{}", value)) + self.record_debug(field, &format_args!("{value}")) } } @@ -498,7 +510,7 @@ impl<'a> Visit for GlogVisitor<'a> { &format_args!("{}, {}.sources: {}", value, field, ErrorSourceList(source),), ) } else { - self.record_debug(field, &format_args!("{}", value)) + self.record_debug(field, &format_args!("{value}")) } } @@ -538,7 +550,7 @@ impl<'a> fmt::Display for ErrorSourceList<'a> { let mut list = f.debug_list(); let mut curr = Some(self.0); while let Some(curr_err) = curr { - list.entry(&format_args!("{}", curr_err)); + list.entry(&format_args!("{curr_err}")); curr = curr_err.source(); } list.finish()