109 lines
3.2 KiB
Rust
109 lines
3.2 KiB
Rust
use std::fmt::Result;
|
|
|
|
use ansi_term::Color;
|
|
use time::format_description::FormatItem;
|
|
use time::macros::format_description;
|
|
use time::OffsetDateTime;
|
|
use tracing::field::Field;
|
|
use tracing::{Event, Level, Metadata, Subscriber};
|
|
use tracing_error::ErrorLayer;
|
|
use tracing_subscriber::filter::FilterFn;
|
|
use tracing_subscriber::fmt::format::{debug_fn, Writer};
|
|
use tracing_subscriber::fmt::{self, FmtContext, FormatEvent, FormatFields};
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
use tracing_subscriber::prelude::*;
|
|
use tracing_subscriber::registry::LookupSpan;
|
|
use tracing_subscriber::EnvFilter;
|
|
|
|
pub const TIME_FORMAT: &[FormatItem] = format_description!("[hour]:[minute]:[second]");
|
|
|
|
pub fn format_fields(w: &mut Writer<'_>, field: &Field, val: &dyn std::fmt::Debug) -> Result {
|
|
if field.name() == "message" {
|
|
write!(w, "{:?}", val)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn filter_fields(metadata: &Metadata<'_>) -> bool {
|
|
metadata
|
|
.fields()
|
|
.iter()
|
|
.any(|field| field.name() == "message")
|
|
}
|
|
|
|
pub struct Formatter;
|
|
|
|
impl<S, N> FormatEvent<S, N> for Formatter
|
|
where
|
|
S: Subscriber + for<'a> LookupSpan<'a>,
|
|
N: for<'a> FormatFields<'a> + 'static,
|
|
{
|
|
fn format_event(
|
|
&self,
|
|
ctx: &FmtContext<'_, S, N>,
|
|
mut writer: Writer<'_>,
|
|
event: &Event<'_>,
|
|
) -> Result {
|
|
let meta = event.metadata();
|
|
|
|
let time = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
|
|
let time = time.format(TIME_FORMAT).map_err(|_| std::fmt::Error)?;
|
|
|
|
let level = meta.level();
|
|
// Sadly, tracing's `Level` is a struct, not an enum, so we can't properly `match` it.
|
|
let color = if *level == Level::TRACE {
|
|
Color::Purple
|
|
} else if *level == Level::DEBUG {
|
|
Color::Blue
|
|
} else if *level == Level::INFO {
|
|
Color::Green
|
|
} else if *level == Level::WARN {
|
|
Color::Yellow
|
|
} else if *level == Level::ERROR {
|
|
Color::Red
|
|
} else {
|
|
unreachable!()
|
|
};
|
|
|
|
write!(
|
|
writer,
|
|
"[{}] [{:>5}] ",
|
|
time,
|
|
color.bold().paint(format!("{}", level))
|
|
)?;
|
|
|
|
ctx.field_format().format_fields(writer.by_ref(), event)?;
|
|
|
|
writeln!(writer)
|
|
}
|
|
}
|
|
|
|
pub fn create_tracing_subscriber() {
|
|
let env_layer =
|
|
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::try_new("info").unwrap());
|
|
|
|
let (dev_stdout_layer, prod_stdout_layer, filter_layer) = if cfg!(debug_assertions) {
|
|
let fmt_layer = fmt::layer().pretty();
|
|
(Some(fmt_layer), None, None)
|
|
} else {
|
|
// Creates a layer that
|
|
// - only prints events that contain a message
|
|
// - does not print fields
|
|
// - does not print spans/targets
|
|
// - only prints time, not date
|
|
let fmt_layer = fmt::layer()
|
|
.event_format(Formatter)
|
|
.fmt_fields(debug_fn(format_fields));
|
|
|
|
(None, Some(fmt_layer), Some(FilterFn::new(filter_fields)))
|
|
};
|
|
|
|
tracing_subscriber::registry()
|
|
.with(filter_layer)
|
|
.with(env_layer)
|
|
.with(dev_stdout_layer)
|
|
.with(prod_stdout_layer)
|
|
.with(ErrorLayer::new(fmt::format::Pretty::default()))
|
|
.init();
|
|
}
|