1pub(crate) mod format;
2pub mod time;
3
4use crate::time::FormatTime;
5use format::{write_span_mode, Buffers, ColorLevel, Config, FmtEvent, SpanMode};
6
7use nu_ansi_term::{Color, Style};
8use std::{
9 fmt::{self, Write as _},
10 io::{self, IsTerminal},
11 iter::Fuse,
12 mem,
13 sync::Mutex,
14 time::Instant,
15};
16use tracing_core::{
17 field::{Field, Visit},
18 span::{Attributes, Id},
19 Event, Subscriber,
20};
21#[cfg(feature = "tracing-log")]
22use tracing_log::NormalizeEvent;
23use tracing_subscriber::{
24 fmt::MakeWriter,
25 layer::{Context, Layer},
26 registry::{LookupSpan, ScopeFromRoot, SpanRef},
27};
28
29pub(crate) struct Data {
31 start: Instant,
32 kvs: Vec<(&'static str, String)>,
33 written: bool,
34}
35
36impl Data {
37 pub fn new(attrs: &Attributes<'_>, written: bool) -> Self {
38 let mut span = Self {
39 start: Instant::now(),
40 kvs: Vec::new(),
41 written,
42 };
43 attrs.record(&mut span);
44 span
45 }
46}
47
48impl Visit for Data {
49 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
50 self.kvs.push((field.name(), format!("{:?}", value)))
51 }
52}
53
54#[derive(Debug)]
55pub struct HierarchicalLayer<W = fn() -> io::Stderr, FT = ()>
56where
57 W: for<'writer> MakeWriter<'writer> + 'static,
58 FT: FormatTime,
59{
60 make_writer: W,
61 bufs: Mutex<Buffers>,
62 config: Config,
63 timer: FT,
64}
65
66impl Default for HierarchicalLayer {
67 fn default() -> Self {
68 Self::new(2)
69 }
70}
71
72impl HierarchicalLayer<fn() -> io::Stderr> {
73 pub fn new(indent_amount: usize) -> Self {
74 let ansi = io::stderr().is_terminal();
75 let config = Config {
76 ansi,
77 indent_amount,
78 ..Default::default()
79 };
80 Self {
81 make_writer: io::stderr,
82 bufs: Mutex::new(Buffers::new()),
83 config,
84 timer: (),
85 }
86 }
87}
88
89impl<W, FT> HierarchicalLayer<W, FT>
90where
91 W: for<'writer> MakeWriter<'writer> + 'static,
92 FT: FormatTime,
93{
94 pub fn with_ansi(self, ansi: bool) -> Self {
96 Self {
97 config: self.config.with_ansi(ansi),
98 ..self
99 }
100 }
101
102 pub fn with_writer<W2>(self, make_writer: W2) -> HierarchicalLayer<W2, FT>
103 where
104 W2: for<'writer> MakeWriter<'writer>,
105 {
106 HierarchicalLayer {
107 make_writer,
108 config: self.config,
109 bufs: self.bufs,
110 timer: self.timer,
111 }
112 }
113
114 pub fn with_indent_amount(self, indent_amount: usize) -> Self {
115 let config = Config {
116 indent_amount,
117 ..self.config
118 };
119 Self { config, ..self }
120 }
121
122 pub fn with_indent_lines(self, indent_lines: bool) -> Self {
124 Self {
125 config: self.config.with_indent_lines(indent_lines),
126 ..self
127 }
128 }
129
130 pub fn with_timer<FT2: FormatTime>(self, timer: FT2) -> HierarchicalLayer<W, FT2> {
132 HierarchicalLayer {
133 make_writer: self.make_writer,
134 config: self.config,
135 bufs: self.bufs,
136 timer,
137 }
138 }
139
140 pub fn with_targets(self, targets: bool) -> Self {
143 Self {
144 config: self.config.with_targets(targets),
145 ..self
146 }
147 }
148
149 pub fn with_thread_ids(self, thread_ids: bool) -> Self {
152 Self {
153 config: self.config.with_thread_ids(thread_ids),
154 ..self
155 }
156 }
157
158 pub fn with_thread_names(self, thread_names: bool) -> Self {
161 Self {
162 config: self.config.with_thread_names(thread_names),
163 ..self
164 }
165 }
166
167 pub fn with_wraparound(self, wraparound: usize) -> Self {
171 Self {
172 config: self.config.with_wraparound(wraparound),
173 ..self
174 }
175 }
176
177 pub fn with_verbose_entry(self, verbose_entry: bool) -> Self {
181 Self {
182 config: self.config.with_verbose_entry(verbose_entry),
183 ..self
184 }
185 }
186
187 pub fn with_verbose_exit(self, verbose_exit: bool) -> Self {
191 Self {
192 config: self.config.with_verbose_exit(verbose_exit),
193 ..self
194 }
195 }
196
197 pub fn with_span_retrace(self, enabled: bool) -> Self {
202 Self {
203 config: self.config.with_span_retrace(enabled),
204 ..self
205 }
206 }
207
208 pub fn with_deferred_spans(self, enabled: bool) -> Self {
212 Self {
213 config: self.config.with_deferred_spans(enabled),
214 ..self
215 }
216 }
217
218 pub fn with_span_modes(self, enabled: bool) -> Self {
220 Self {
221 config: self.config.with_span_modes(enabled),
222 ..self
223 }
224 }
225
226 pub fn with_bracketed_fields(self, bracketed_fields: bool) -> Self {
229 Self {
230 config: self.config.with_bracketed_fields(bracketed_fields),
231 ..self
232 }
233 }
234
235 pub fn with_higher_precision(self, higher_precision: bool) -> Self {
237 Self {
238 config: self.config.with_higher_precision(higher_precision),
239 ..self
240 }
241 }
242
243 fn styled(&self, style: Style, text: impl AsRef<str>) -> String {
244 if self.config.ansi {
245 style.paint(text.as_ref()).to_string()
246 } else {
247 text.as_ref().to_string()
248 }
249 }
250
251 fn print_kvs<'a, I, V>(&self, buf: &mut impl fmt::Write, kvs: I) -> fmt::Result
252 where
253 I: IntoIterator<Item = (&'a str, V)>,
254 V: fmt::Display + 'a,
255 {
256 let mut kvs = kvs.into_iter();
257 if let Some((k, v)) = kvs.next() {
258 if k == "message" {
259 write!(buf, "{}", v)?;
260 } else {
261 write!(buf, "{}={}", k, v)?;
262 }
263 }
264 for (k, v) in kvs {
265 write!(buf, ", {}={}", k, v)?;
266 }
267 Ok(())
268 }
269
270 fn write_retrace_span<'a, S>(
272 &self,
273 new_span: &SpanRef<'a, S>,
274 bufs: &mut Buffers,
275 ctx: &'a Context<S>,
276 ) where
277 S: Subscriber + for<'new_span> LookupSpan<'new_span>,
278 {
279 let should_write = if self.config.deferred_spans {
280 if let Some(data) = new_span.extensions_mut().get_mut::<Data>() {
281 !data.written
282 } else {
283 false
284 }
285 } else {
286 false
287 };
288
289 if self.config.span_retrace || should_write {
292 let old_span_id = bufs.current_span.replace((new_span.id()).clone());
293 let old_span_id = old_span_id.as_ref();
294
295 if Some(&new_span.id()) != old_span_id {
296 let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
297 let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();
298
299 let new_path = scope_path(new_span);
300
301 let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());
303
304 for (i, span) in new_path.enumerate() {
305 let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
307 mem::replace(&mut data.written, true)
308 } else {
309 false
313 };
314
315 if i == 0 && self.config.verbose_entry {
317 if let Some(parent) = &span.parent() {
318 self.write_span_info(parent, bufs, SpanMode::PreOpen);
319 }
320 }
321 let verbose = self.config.verbose_entry && i == 0;
322
323 self.write_span_info(
324 &span,
325 bufs,
326 if was_written {
327 SpanMode::Retrace { verbose }
328 } else {
329 SpanMode::Open { verbose }
330 },
331 )
332 }
333 }
334 }
335 }
336
337 fn write_span_info<S>(&self, span: &SpanRef<S>, bufs: &mut Buffers, style: SpanMode)
338 where
339 S: Subscriber + for<'span> LookupSpan<'span>,
340 {
341 let ext = span.extensions();
342 let data = ext.get::<Data>().expect("span does not have data");
343
344 let mut current_buf = &mut bufs.current_buf;
345
346 if self.config.span_modes {
347 write_span_mode(current_buf, style)
348 }
349
350 let indent = scope_path(span).skip(1).count();
351
352 let should_write = match style {
353 SpanMode::Open { .. } | SpanMode::Event => true,
354 SpanMode::PreOpen { .. } if self.config.verbose_entry => true,
356 SpanMode::Close { verbose } => verbose,
357 SpanMode::Retrace { .. } => true,
359 SpanMode::PostClose => true,
361 _ => false,
362 };
363
364 if should_write {
365 if self.config.targets {
366 let target = span.metadata().target();
367 write!(
368 &mut current_buf,
369 "{}::",
370 self.styled(Style::new().dimmed(), target,),
371 )
372 .expect("Unable to write to buffer");
373 }
374
375 write!(
376 current_buf,
377 "{name}",
378 name = self.styled(Style::new().fg(Color::Green).bold(), span.metadata().name())
379 )
380 .unwrap();
381 if self.config.bracketed_fields {
382 write!(
383 current_buf,
384 "{}",
385 self.styled(Style::new().fg(Color::Green).bold(), "{") )
387 .unwrap();
388 } else {
389 write!(current_buf, " ").unwrap();
390 }
391 self.print_kvs(&mut current_buf, data.kvs.iter().map(|(k, v)| (*k, v)))
392 .unwrap();
393 if self.config.bracketed_fields {
394 write!(
395 current_buf,
396 "{}",
397 self.styled(Style::new().fg(Color::Green).bold(), "}") )
399 .unwrap();
400 }
401 }
402
403 bufs.indent_current(indent, &self.config, style);
404 let writer = self.make_writer.make_writer();
405 bufs.flush_current_buf(writer)
406 }
407
408 fn get_timestamp<S>(&self, span: SpanRef<S>) -> Option<String>
409 where
410 S: Subscriber + for<'span> LookupSpan<'span>,
411 {
412 let ext = span.extensions();
413 let data = ext
414 .get::<Data>()
415 .expect("Data cannot be found in extensions");
416
417 if self.config.higher_precision {
418 Some(self.format_timestamp_with_decimals(data.start))
419 } else {
420 Some(self.format_timestamp(data.start))
421 }
422 }
423
424 fn format_timestamp(&self, start: std::time::Instant) -> String {
425 let elapsed = start.elapsed();
426 let millis = elapsed.as_millis();
427 let secs = elapsed.as_secs();
428
429 let (n, unit) = if millis < 1000 {
434 (millis as _, "ms")
435 } else if secs < 60 {
436 (secs, "s ")
437 } else {
438 (secs / 60, "m ")
439 };
440
441 let timestamp = format!("{n:>3}");
442 self.style_timestamp(timestamp, unit)
443 }
444
445 fn format_timestamp_with_decimals(&self, start: std::time::Instant) -> String {
446 let secs = start.elapsed().as_secs_f64();
447
448 let (n, unit) = if secs < 0.001 {
453 (secs * 1_000_000.0, "μs")
454 } else if secs < 1.0 {
455 (secs * 1_000.0, "ms")
456 } else {
457 (secs, "s ")
458 };
459
460 let timestamp = format!(" {n:.2}");
461 self.style_timestamp(timestamp, unit)
462 }
463
464 fn style_timestamp(&self, timestamp: String, unit: &str) -> String {
465 format!(
466 "{timestamp}{unit} ",
467 timestamp = self.styled(Style::new().dimmed(), timestamp),
468 unit = self.styled(Style::new().dimmed(), unit),
469 )
470 }
471}
472
473impl<S, W, FT> Layer<S> for HierarchicalLayer<W, FT>
474where
475 S: Subscriber + for<'span> LookupSpan<'span>,
476 W: for<'writer> MakeWriter<'writer> + 'static,
477 FT: FormatTime + 'static,
478{
479 fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
480 let span = ctx.span(id).expect("in new_span but span does not exist");
481
482 if span.extensions().get::<Data>().is_none() {
483 let data = Data::new(attrs, !self.config.deferred_spans);
484 span.extensions_mut().insert(data);
485 }
486
487 if self.config.deferred_spans {
489 return;
490 }
491
492 let bufs = &mut *self.bufs.lock().unwrap();
493
494 bufs.current_span = Some(span.id());
496
497 if self.config.verbose_entry {
498 if let Some(span) = span.parent() {
499 self.write_span_info(&span, bufs, SpanMode::PreOpen);
500 }
501 }
502
503 self.write_span_info(
504 &span,
505 bufs,
506 SpanMode::Open {
507 verbose: self.config.verbose_entry,
508 },
509 );
510 }
511
512 fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
513 let span = ctx.current_span();
514 let span_id = span.id();
515 let span = span_id.and_then(|id| ctx.span(id));
516
517 let mut guard = self.bufs.lock().unwrap();
518 let bufs = &mut *guard;
519
520 if let Some(new_span) = &span {
521 self.write_retrace_span(new_span, bufs, &ctx);
522 }
523
524 let mut event_buf = &mut bufs.current_buf;
525
526 {
529 let prev_buffer_len = event_buf.len();
530
531 self.timer
532 .format_time(&mut event_buf)
533 .expect("Unable to write time to buffer");
534
535 if prev_buffer_len < event_buf.len() {
537 write!(event_buf, " ").expect("Unable to write to buffer");
538 }
539 }
540
541 let indent = ctx
543 .event_scope(event)
544 .map(|scope| scope.count())
545 .unwrap_or(0);
546
547 if let Some(span) = span {
550 if let Some(timestamp) = self.get_timestamp(span) {
551 write!(&mut event_buf, "{}", timestamp).expect("Unable to write to buffer");
552 }
553 }
554
555 #[cfg(feature = "tracing-log")]
556 let normalized_meta = event.normalized_metadata();
557 #[cfg(feature = "tracing-log")]
558 let metadata = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
559 #[cfg(not(feature = "tracing-log"))]
560 let metadata = event.metadata();
561
562 let level = metadata.level();
563 let level = if self.config.ansi {
564 ColorLevel(level).to_string()
565 } else {
566 level.to_string()
567 };
568
569 write!(&mut event_buf, "{level}", level = level).expect("Unable to write to buffer");
570
571 if self.config.targets {
572 let target = metadata.target();
573 write!(
574 &mut event_buf,
575 " {}",
576 self.styled(Style::new().dimmed(), target,),
577 )
578 .expect("Unable to write to buffer");
579 }
580
581 let mut visitor = FmtEvent { comma: false, bufs };
582 event.record(&mut visitor);
583 visitor
584 .bufs
585 .indent_current(indent, &self.config, SpanMode::Event);
586 let writer = self.make_writer.make_writer();
587 bufs.flush_current_buf(writer)
588 }
589
590 fn on_close(&self, id: Id, ctx: Context<S>) {
591 let bufs = &mut *self.bufs.lock().unwrap();
592
593 let span = ctx.span(&id).expect("invalid span in on_close");
594
595 if self.config.deferred_spans
597 && span.extensions().get::<Data>().map(|v| v.written) != Some(true)
598 {
599 return;
600 }
601
602 self.write_span_info(
605 &span,
606 bufs,
607 SpanMode::Close {
608 verbose: self.config.verbose_exit,
609 },
610 );
611
612 if let Some(parent_span) = span.parent() {
613 bufs.current_span = Some(parent_span.id());
614 if self.config.verbose_exit {
615 self.write_span_info(&parent_span, bufs, SpanMode::PostClose);
618 }
619 }
620 }
621}
622
623fn scope_path<'a, R: LookupSpan<'a>>(span: &SpanRef<'a, R>) -> ScopeFromRoot<'a, R> {
624 span.scope().from_root()
625}
626
627struct DifferenceIter<L, R, F> {
629 left: Fuse<L>,
630 right: R,
631 compare: F,
632}
633
634impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U>
635 DifferenceIter<L, R, F>
636{
637 fn new(left: L, right: R, compare: F) -> Self {
638 Self {
639 left: left.fuse(),
640 right,
641 compare,
642 }
643 }
644}
645
646impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U> Iterator
647 for DifferenceIter<L, R, F>
648{
649 type Item = T;
650
651 fn next(&mut self) -> Option<Self::Item> {
652 loop {
653 let left = self.left.next();
654 let right = self.right.next()?;
655
656 if left.as_ref().map(&self.compare) != Some((self.compare)(&right)) {
657 return Some(right);
658 }
659 }
660 }
661}