1use crate::logging::fast_local_time::FastLocalTime;
20use console::style;
21use std::fmt;
22use tracing::{Event, Level, Subscriber};
23use tracing_log::NormalizeEvent;
24use tracing_subscriber::{
25 fmt::{format, time::FormatTime, FmtContext, FormatEvent, FormatFields},
26 registry::LookupSpan,
27};
28
29pub struct EventFormat<T = FastLocalTime> {
31 pub timer: T,
33 pub display_target: bool,
35 pub display_level: bool,
37 pub display_thread_name: bool,
39 pub dup_to_stdout: bool,
41}
42
43impl<T> EventFormat<T>
44where
45 T: FormatTime,
46{
47 pub(crate) fn format_event_custom<'b, 'w, S, N>(
51 &self,
52 ctx: &FmtContext<'b, S, N>,
53 mut writer: format::Writer<'w>,
54 event: &Event,
55 ) -> fmt::Result
56 where
57 S: Subscriber + for<'a> LookupSpan<'a>,
58 N: for<'a> FormatFields<'a> + 'static,
59 {
60 let normalized_meta = event.normalized_metadata();
61 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
62 time::write(&self.timer, &mut format::Writer::new(&mut writer))?;
63
64 if self.display_level {
65 let fmt_level = FmtLevel::new(meta.level());
66 write!(writer, "{} ", fmt_level)?;
67 }
68
69 if self.display_thread_name {
70 let current_thread = std::thread::current();
71 match current_thread.name() {
72 Some(name) => {
73 write!(&mut writer, "{} ", FmtThreadName::new(name))?;
74 },
75 None => {
77 write!(&mut writer, "{:0>2?} ", current_thread.id())?;
78 },
79 }
80 }
81
82 if self.display_target {
83 write!(&mut writer, "{}: ", meta.target())?;
84 }
85
86 if let Some(span) = ctx.lookup_current() {
88 for span in span.scope() {
89 let exts = span.extensions();
90 if let Some(prefix) = exts.get::<super::layers::Prefix>() {
91 write!(&mut writer, "{}", prefix.as_str())?;
92 break
93 }
94 }
95 }
96
97 ctx.format_fields(format::Writer::new(&mut writer), event)?;
98 writeln!(&mut writer)?;
99
100 Ok(())
101 }
102}
103
104impl<S, N, T> FormatEvent<S, N> for EventFormat<T>
108where
109 S: Subscriber + for<'a> LookupSpan<'a>,
110 N: for<'a> FormatFields<'a> + 'static,
111 T: FormatTime,
112{
113 fn format_event(
114 &self,
115 ctx: &FmtContext<S, N>,
116 mut writer: format::Writer<'_>,
117 event: &Event,
118 ) -> fmt::Result {
119 if self.dup_to_stdout &&
120 (event.metadata().level() == &Level::INFO ||
121 event.metadata().level() == &Level::WARN ||
122 event.metadata().level() == &Level::ERROR)
123 {
124 let mut out = String::new();
125 let buf_writer = format::Writer::new(&mut out);
126 self.format_event_custom(ctx, buf_writer, event)?;
127 writer.write_str(&out)?;
128 print!("{}", out);
129 Ok(())
130 } else {
131 self.format_event_custom(ctx, writer, event)
132 }
133 }
134}
135
136struct FmtLevel<'a> {
137 level: &'a Level,
138}
139
140impl<'a> FmtLevel<'a> {
141 pub(crate) fn new(level: &'a Level) -> Self {
142 Self { level }
143 }
144}
145
146const TRACE_STR: &str = "TRACE";
147const DEBUG_STR: &str = "DEBUG";
148const INFO_STR: &str = " INFO";
149const WARN_STR: &str = " WARN";
150const ERROR_STR: &str = "ERROR";
151
152impl<'a> fmt::Display for FmtLevel<'a> {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 match *self.level {
155 Level::TRACE => write!(f, "{}", style(TRACE_STR).magenta()),
156 Level::DEBUG => write!(f, "{}", style(DEBUG_STR).blue()),
157 Level::INFO => write!(f, "{}", style(INFO_STR).green()),
158 Level::WARN => write!(f, "{}", style(WARN_STR).yellow()),
159 Level::ERROR => write!(f, "{}", style(ERROR_STR).red()),
160 }
161 }
162}
163
164struct FmtThreadName<'a> {
165 name: &'a str,
166}
167
168impl<'a> FmtThreadName<'a> {
169 pub(crate) fn new(name: &'a str) -> Self {
170 Self { name }
171 }
172}
173
174impl<'a> fmt::Display for FmtThreadName<'a> {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 use std::sync::atomic::{
180 AtomicUsize,
181 Ordering::{AcqRel, Acquire, Relaxed},
182 };
183
184 static MAX_LEN: AtomicUsize = AtomicUsize::new(0);
187 let len = self.name.len();
188 let mut max_len = MAX_LEN.load(Relaxed);
190
191 while len > max_len {
192 match MAX_LEN.compare_exchange(max_len, len, AcqRel, Acquire) {
195 Ok(_) => break,
197 Err(actual) => max_len = actual,
202 }
203 }
204
205 write!(f, "{:>width$}", self.name, width = max_len)
207 }
208}
209
210mod time {
214 use std::fmt;
215 use tracing_subscriber::fmt::{format, time::FormatTime};
216
217 pub(crate) fn write<T>(timer: T, writer: &mut format::Writer<'_>) -> fmt::Result
218 where
219 T: FormatTime,
220 {
221 if console::colors_enabled() {
222 write!(writer, "\x1B[2m")?;
223 timer.format_time(writer)?;
224 write!(writer, "\x1B[0m")?;
225 } else {
226 timer.format_time(writer)?;
227 }
228
229 writer.write_char(' ')?;
230 Ok(())
231 }
232}