1#![feature(unboxed_closures)]
2#![feature(fn_traits)]
3
4#![doc = include_str!("../Readme.md")]
5
6use tracing::{Id, Level, Event, span, Metadata, Subscriber};
7use tracing::subscriber::Interest;
8use tracing::field::{Field, Visit};
9use std::ops::RangeInclusive;
10use std::fmt::{Display, Write};
11use std::sync::atomic::AtomicUsize;
12use core::*;
13
14#[cfg(feature = "print_colored")]
15use owo_colors::{AnsiColors, OwoColorize, Stream};
16
17mod core;
18
19#[cfg(feature = "print_colored")]
24const SPAN_COLORS: [AnsiColors; 6] = [
25 AnsiColors::BrightBlue,
26 AnsiColors::BrightCyan,
27 AnsiColors::BrightMagenta,
28 AnsiColors::Yellow,
29 AnsiColors::BrightGreen,
30 AnsiColors::Red,
31];
32
33#[cfg(not(feature = "print_colored"))]
34#[derive(Copy, Clone)]
35struct AnsiColors;
36
37fn colorize(color: Option<AnsiColors>, message: String) -> String {
45 match color {
46 #[cfg(feature = "print_colored")]
47 Some(index) => {
48 message
49 .if_supports_color(Stream::Stdout, |text| text.color(index))
50 .to_string()
51 },
52 #[cfg(not(feature = "print_colored"))]
53 Some(_) => unreachable!(),
54 None => message
55 }
56}
57
58struct PrintToStdout;
59
60impl FnOnce<(String,)> for PrintToStdout {
61 type Output = ();
62
63 extern "rust-call" fn call_once(self, args: (String,)) {
64 self.call(args)
65 }
66}
67
68impl<'a> FnMut<(String,)> for PrintToStdout {
69 extern "rust-call" fn call_mut(&mut self, args: (String,)) {
70 self.call(args)
71 }
72}
73
74impl<'a> Fn<(String,)> for PrintToStdout {
75 extern "rust-call" fn call(&self, args: (String,)) {
76 print!("{}", args.0);
78 std::io::Write::flush(&mut std::io::stdout()).unwrap()
79 }
80}
81
82struct SpanData {
83 desc: FieldRecorder,
84 depth: usize,
85 metadata: &'static Metadata<'static>,
86 color: Option<AnsiColors>,
87 #[allow(unused)]
90 color_counter: Option<AtomicUsize>
91}
92
93impl SpanData {
94
95 #[cfg(feature = "print_colored")]
96 fn color_for_child(&self) -> Option<AnsiColors> {
97 if let Some(color_counter) = &self.color_counter {
98 debug_assert_eq!(0, self.depth);
99 Some(SPAN_COLORS[color_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) % SPAN_COLORS.len()])
100 } else {
101 self.color
102 }
103 }
104
105 #[cfg(not(feature = "print_colored"))]
106 fn color_for_child(&self) -> Option<AnsiColors> {
107 None
108 }
109}
110
111pub struct DelayedLogger {
129 base: DelayedLoggerImpl<SpanData, PrintToStdout>,
130 levels: RangeInclusive<Level>,
131 max_depth: usize
132}
133
134impl DelayedLogger {
135
136 pub fn new(max_depth: usize, silent_period: u64, levels: RangeInclusive<Level>) -> Self {
145 Self {
146 base: DelayedLoggerImpl::new(silent_period, PrintToStdout),
147 levels: levels,
148 max_depth: max_depth
149 }
150 }
151
152 pub fn init(max_depth: usize, silent_period: u64, levels: RangeInclusive<Level>) {
157 tracing::subscriber::set_global_default(Self::new(max_depth, silent_period, levels)).unwrap()
158 }
159
160 pub fn init_test() {
165 _ = tracing::subscriber::set_global_default(Self::new(4, 100000, Level::ERROR..=Level::TRACE));
166 }
167}
168
169#[derive(Clone)]
170struct FieldRecorder {
171 message: Option<String>,
172 fields: Option<String>
173}
174
175impl FieldRecorder {
176
177 fn new() -> Self {
178 Self { message: None, fields: None }
179 }
180
181 fn to_string(self) -> String {
182 match (self.message, self.fields) {
183 (Some(mut message), Some(fields)) => {
184 write!(&mut message, "({})", fields).unwrap();
185 message
186 },
187 (Some(mut message), None) => {
188 write!(&mut message, ".").unwrap();
189 message
190 },
191 (None, Some(fields)) => {
192 format!("({})", fields)
193 },
194 (None, None) => ".".to_owned()
195 }
196 }
197}
198
199impl Display for FieldRecorder {
200
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 if let Some(message) = &self.message {
203 write!(f, "{}", message)?;
204 }
205 if let Some(fields) = &self.fields {
206 write!(f, "({})", fields)
207 } else {
208 write!(f, ".")
209 }
210 }
211}
212
213impl Visit for FieldRecorder {
214
215 fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
216 if field.name() == "message" {
217 self.message = Some(format!("{:?}", value));
218 } else {
219 if let Some(fields) = &mut self.fields {
220 write!(fields, ", {}={:?}", field.name(), value).unwrap();
221 } else {
222 self.fields = Some(format!("{}={:?}", field.name(), value));
223 }
224 }
225 }
226}
227
228impl Subscriber for DelayedLogger {
229
230 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
231 if self.levels.contains(metadata.level()) {
232 Interest::always()
233 } else {
234 Interest::never()
235 }
236 }
237
238 fn enabled(&self, metadata: &Metadata<'_>) -> bool {
239 self.levels.contains(metadata.level())
240 }
241
242 fn current_span(&self) -> tracing_core::span::Current {
243 let mut result = tracing_core::span::Current::none();
244 if let Some(span) = self.base.span_stack().borrow().last().copied() {
245 self.base.span_data(span, |data, _, _| result =
246 tracing_core::span::Current::new(Id::from_non_zero_u64(span), data.metadata)
247 );
248 }
249 return result;
250 }
251
252 fn new_span(&self, span: &span::Attributes<'_>) -> Id {
253 let mut fields = FieldRecorder::new();
254 span.record(&mut fields);
255 fields.message = Some(span.metadata().name().to_owned());
256
257 let id = if let Some(parent_id) = span.parent() {
258 let mut depth = 0;
259 let mut color = None;
260 self.base.span_data(parent_id.into_non_zero_u64(), |data, _, _| {
261 depth = data.depth + 1;
262 color = data.color_for_child();
263 });
264 self.base.create_span_with_parent(SpanData {
265 color_counter: if depth == 0 { Some(AtomicUsize::new(0)) } else { None },
266 desc: fields,
267 metadata: span.metadata(),
268 depth: depth,
269 color: color
270 }, Some(parent_id.into_non_zero_u64()))
271 } else {
272 self.base.create_span(|parent| {
273 let (depth, color) = if let Some((parent_data, _)) = parent {
274 (parent_data.depth + 1, parent_data.color_for_child())
275 } else {
276 (0, None)
277 };
278 SpanData {
279 color_counter: if depth == 0 { Some(AtomicUsize::new(0)) } else { None },
280 desc: fields,
281 metadata: span.metadata(),
282 depth: depth,
283 color: color
284 }
285 })
286 };
287
288 return Id::from_non_zero_u64(id);
289 }
290
291 fn record(&self, _span: &Id, _values: &span::Record<'_>) {
292 unimplemented!()
293 }
294
295 fn record_follows_from(&self, _span: &Id, _follows: &Id) {
296 }
298
299 fn event(&self, event: &Event<'_>) {
300 if self.levels.contains(event.metadata().level()) {
301 let mut is_within_depth = false;
302 let mut color = None;
303 if let Some(span) = self.base.span_stack().borrow().last().copied() {
304 self.base.span_data(span, |data, _, _| if data.depth < self.max_depth {
305 is_within_depth = true;
306 color = data.color;
307 });
308 if is_within_depth {
309 let mut fields = FieldRecorder::new();
310 event.record(&mut fields);
311 self.base.send_message(colorize(color, fields.to_string()), span);
312 }
313 } else {
314 let mut fields = FieldRecorder::new();
315 event.record(&mut fields);
316 PrintToStdout(fields.to_string())
317 }
318 }
319 }
320
321 fn enter(&self, span: &Id) {
322 self.base.enter(span.into_non_zero_u64());
323 let mut message = None;
324 self.base.span_data(span.into_non_zero_u64(), |data, _, _| if data.depth < self.max_depth {
325 message = Some(colorize(data.color, data.desc.clone().to_string()));
326 } else if data.depth == self.max_depth {
327 message = Some(colorize(data.color, format!("{}...", data.desc)));
328 });
329 if let Some(message) = message {
330 self.base.send_message(message, span.into_non_zero_u64());
331 }
332 }
333
334 fn exit(&self, span: &Id) {
335 let mut message = None;
336 self.base.span_data(span.into_non_zero_u64(), |data, _, running_time| if data.depth == 0 {
337 message = Some(format!("done({} us)\n", running_time.as_micros()));
338 } else if data.depth <= self.max_depth {
339 message = Some(colorize(data.color, format!("done({} us)", running_time.as_micros())));
340 });
341 if let Some(message) = message {
342 self.base.send_message(message, span.into_non_zero_u64());
343 }
344 self.base.exit(span.into_non_zero_u64())
345 }
346
347 fn clone_span(&self, id: &Id) -> Id {
348 self.base.clone_span(id.into_non_zero_u64());
349 return id.clone();
350 }
351
352 fn try_close(&self, id: Id) -> bool {
353 self.base.delete_span(id.into_non_zero_u64())
354 }
355}