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