1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
use std::{fmt, io, time::Instant};
use tracing::{
    field::{Field, Visit},
    Event, Level, Subscriber,
};
use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};

#[derive(Debug, Default)]
struct FmtEventVisitor {
    message: String,
}

impl Visit for FmtEventVisitor {
    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
        match field.name() {
            "message" => self.message = format!("{:?}", value),
            _ => {}
        }
    }
}

enum StandardOutput {
    Out(io::Stdout),
    Err(io::Stderr),
}

impl StandardOutput {
    fn new(level: &Level) -> Self {
        match *level {
            Level::ERROR | Level::WARN => Self::Err(io::stderr()),
            _ => Self::Out(io::stdout()),
        }
    }

    fn get_dyn_ref(&mut self) -> &mut dyn io::Write {
        match self {
            Self::Out(out) => out,
            Self::Err(err) => err,
        }
    }
}

/// Output messages to standard streams.
///
/// ERROR/WARN go to stderr.
/// All others to go to stdout.
pub struct FmtLayer {
    start: Instant,
}

impl FmtLayer {
    pub fn new() -> Self {
        FmtLayer {
            start: Instant::now(),
        }
    }
}

impl<S> Layer<S> for FmtLayer
where
    S: Subscriber + for<'span> LookupSpan<'span>,
{
    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
        let now = Instant::now();
        let time = now - self.start;

        let mut visitor = FmtEventVisitor::default();
        event.record(&mut visitor);

        let mut span_string = String::new();
        for span in ctx.scope() {
            if !span_string.is_empty() {
                span_string.push_str(" | ");
            }
            span_string.push_str(span.name());
        }

        let metadata = event.metadata();
        let level = match *metadata.level() {
            Level::ERROR => "ERROR",
            Level::WARN => "WARN",
            Level::INFO => "INFO",
            Level::DEBUG => "DEBUG",
            Level::TRACE => "TRACE",
        };

        let module = metadata.module_path().unwrap_or("no module");

        let mut output = StandardOutput::new(metadata.level());
        let output_ref = output.get_dyn_ref();

        writeln!(
            output_ref,
            "[{:.6} {}]({})({}): {}",
            time.as_secs_f64(),
            level,
            span_string,
            module,
            visitor.message,
        )
        .unwrap();
    }
}