use std::io;
use anyhow::Context;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{
Layer, Registry,
filter::{Targets, filter_fn},
fmt::{MakeWriter, time},
layer::SubscriberExt,
};
use tracing_tree::HierarchicalLayer;
use crate::tracing::hprof;
use crate::tracing::json;
#[derive(Debug)]
pub struct Config<T> {
pub writer: T,
pub filter: String,
pub chalk_filter: Option<String>,
pub profile_filter: Option<String>,
pub json_profile_filter: Option<String>,
}
impl<T> Config<T>
where
T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
{
pub fn init(self) -> anyhow::Result<()> {
let targets_filter: Targets = self
.filter
.parse()
.with_context(|| format!("invalid log filter: `{}`", self.filter))?;
let writer = self.writer;
let ra_fmt_layer = tracing_subscriber::fmt::layer()
.with_target(false)
.with_ansi(false)
.with_writer(writer);
let ra_fmt_layer = match time::OffsetTime::local_rfc_3339() {
Ok(timer) => {
ra_fmt_layer.with_timer(timer).boxed()
}
Err(_) => {
ra_fmt_layer.boxed()
}
}
.with_filter(targets_filter);
let chalk_layer = match self.chalk_filter {
Some(chalk_filter) => {
let level: LevelFilter =
chalk_filter.parse().with_context(|| "invalid chalk log filter")?;
let chalk_filter = Targets::new()
.with_target("chalk_solve", level)
.with_target("chalk_ir", level)
.with_target("chalk_recursive", level);
HierarchicalLayer::default()
.with_indent_lines(true)
.with_ansi(false)
.with_indent_amount(2)
.with_writer(io::stderr)
.with_filter(chalk_filter)
.boxed()
}
None => None::<HierarchicalLayer>.with_filter(LevelFilter::OFF).boxed(),
};
let profiler_layer = match self.profile_filter {
Some(spec) => Some(hprof::SpanTree::new(&spec)).with_filter(LevelFilter::INFO),
None => None.with_filter(LevelFilter::OFF),
};
let json_profiler_layer = match self.json_profile_filter {
Some(spec) => {
let filter = json::JsonFilter::from_spec(&spec);
let filter = filter_fn(move |metadata| {
let allowed = match &filter.allowed_names {
Some(names) => names.contains(metadata.name()),
None => true,
};
allowed && metadata.is_span()
});
Some(json::TimingLayer::new(std::io::stderr).with_filter(filter))
}
None => None,
};
let subscriber = Registry::default()
.with(ra_fmt_layer)
.with(json_profiler_layer)
.with(profiler_layer)
.with(chalk_layer);
tracing::subscriber::set_global_default(subscriber)?;
Ok(())
}
}