wgpu_subscriber/
fmt_layer.rs

1use std::{fmt, io, time::Instant};
2use tracing::{
3    field::{Field, Visit},
4    Event, Level, Subscriber,
5};
6use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};
7
8#[derive(Debug, Default)]
9struct FmtEventVisitor {
10    message: String,
11}
12
13impl Visit for FmtEventVisitor {
14    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
15        match field.name() {
16            "message" => self.message = format!("{:?}", value),
17            _ => {}
18        }
19    }
20}
21
22enum StandardOutput {
23    Out(io::Stdout),
24    Err(io::Stderr),
25}
26
27impl StandardOutput {
28    fn new(level: &Level) -> Self {
29        match *level {
30            Level::ERROR | Level::WARN => Self::Err(io::stderr()),
31            _ => Self::Out(io::stdout()),
32        }
33    }
34
35    fn get_dyn_ref(&mut self) -> &mut dyn io::Write {
36        match self {
37            Self::Out(out) => out,
38            Self::Err(err) => err,
39        }
40    }
41}
42
43/// Output messages to standard streams.
44///
45/// ERROR/WARN go to stderr.
46/// All others to go to stdout.
47pub struct FmtLayer {
48    start: Instant,
49}
50
51impl FmtLayer {
52    pub fn new() -> Self {
53        FmtLayer {
54            start: Instant::now(),
55        }
56    }
57}
58
59impl<S> Layer<S> for FmtLayer
60where
61    S: Subscriber + for<'span> LookupSpan<'span>,
62{
63    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
64        let now = Instant::now();
65        let time = now - self.start;
66
67        let mut visitor = FmtEventVisitor::default();
68        event.record(&mut visitor);
69
70        let mut span_string = String::new();
71        for span in ctx.scope() {
72            if !span_string.is_empty() {
73                span_string.push_str(" | ");
74            }
75            span_string.push_str(span.name());
76        }
77
78        let metadata = event.metadata();
79        let level = match *metadata.level() {
80            Level::ERROR => "ERROR",
81            Level::WARN => "WARN",
82            Level::INFO => "INFO",
83            Level::DEBUG => "DEBUG",
84            Level::TRACE => "TRACE",
85        };
86
87        let module = metadata.module_path().unwrap_or("no module");
88
89        let mut output = StandardOutput::new(metadata.level());
90        let output_ref = output.get_dyn_ref();
91
92        writeln!(
93            output_ref,
94            "[{:.6} {}]({})({}): {}",
95            time.as_secs_f64(),
96            level,
97            span_string,
98            module,
99            visitor.message,
100        )
101        .unwrap();
102    }
103}