use crate::{Env, config};
use anyhow::Context;
use std::sync::OnceLock;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{EnvFilter, Layer};
static CONFIG_FILTER: OnceLock<tracing::metadata::LevelFilter> = OnceLock::new();
pub(crate) struct TraceLayer {
pub layer: Box<dyn Layer<tracing_subscriber::Registry> + Send + Sync>,
pub guard: Box<dyn Guard>,
}
pub(crate) trait Guard {}
impl Guard for tracing_appender::non_blocking::WorkerGuard {}
pub(crate) fn logfile(cli_debug: bool) -> anyhow::Result<TraceLayer> {
let file = std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(&crate::config::get().log_path)
.with_context(|| {
format!(
"failed to open logfile at '{}'",
crate::config::get().log_path.display()
)
})?;
let (non_blocking, guard) = tracing_appender::non_blocking(file);
let layer = tracing_subscriber::fmt::Layer::new().with_writer(non_blocking);
let filtered: Box<dyn Layer<tracing_subscriber::Registry> + Send + Sync> = if cli_debug {
Box::new(layer.with_filter(LevelFilter::DEBUG))
} else if let Some(level) = Env::LogLevel
.get::<String>()
.or_else(|| Env::RustLog.get::<String>())
.map(EnvFilter::new)
{
Box::new(layer.with_filter(level))
} else {
Box::new(layer.with_filter(*CONFIG_FILTER.get_or_init(|| *config::get().log_level)))
};
Ok(TraceLayer {
layer: filtered,
guard: Box::new(guard),
})
}
#[cfg(feature = "debug-flame")]
pub(crate) fn flame_file() -> anyhow::Result<std::fs::File> {
let flame_file = "./cnf_traceinfo.folded";
std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(flame_file)
.with_context(|| format!("failed to open flamegraph dump at '{}'", flame_file))
}