use std::fmt;
use tracing::field::Field;
use tracing_indicatif::IndicatifLayer;
use tracing_subscriber::field::{RecordFields, Visit};
use tracing_subscriber::fmt::format::{FormatFields, Writer};
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
pub fn init_logging() -> Result<(), tracing_subscriber::util::TryInitError> {
let indicatif_layer = IndicatifLayer::new();
let filter = EnvFilter::builder()
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.from_env_lossy();
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_writer(indicatif_layer.get_stderr_writer())
.with_timer(tracing_subscriber::fmt::time::uptime())
.with_target(false)
.with_ansi(true)
.fmt_fields(CleanFields)
.compact(),
)
.with(indicatif_layer)
.with(filter)
.try_init()
}
struct CleanFields;
impl<'w> FormatFields<'w> for CleanFields {
fn format_fields<R: RecordFields>(&self, mut writer: Writer<'w>, fields: R) -> fmt::Result {
let mut v = CleanVisitor {
writer: &mut writer,
first: true,
};
fields.record(&mut v);
Ok(())
}
}
struct CleanVisitor<'a, 'w> {
writer: &'a mut Writer<'w>,
first: bool,
}
impl Visit for CleanVisitor<'_, '_> {
fn record_debug(&mut self, field: &Field, val: &dyn fmt::Debug) {
if field.name().starts_with("indicatif.") {
return;
}
if field.name() == "message" {
let _ = write!(self.writer, "{val:?}");
} else {
let sep = if self.first { "" } else { " " };
let _ = write!(self.writer, "{sep}{}={val:?}", field.name());
self.first = false;
}
}
fn record_str(&mut self, field: &Field, val: &str) {
if field.name().starts_with("indicatif.") {
return;
}
if field.name() == "message" {
let _ = write!(self.writer, "{val}");
} else {
let sep = if self.first { "" } else { " " };
let _ = write!(self.writer, "{sep}{}={val:?}", field.name());
self.first = false;
}
}
}