pub mod config;
mod instance;
use ayun_core::{Error, Result};
use tracing_subscriber::{
fmt,
fmt::{time::OffsetTime, writer::MakeWriterExt},
layer::SubscriberExt,
util::SubscriberInitExt,
Layer, Registry,
};
pub struct Logger {
config: config::Logger,
}
impl Logger {
pub fn try_from_config(config: config::Logger) -> Result<Self, Error> {
let mut layers: Vec<Box<dyn Layer<Registry> + Sync + Send>> = Vec::new();
#[cfg(feature = "env-filter")]
with_env_filter(&config, &mut layers)?;
with_fmt_layer(&config, &mut layers)?;
#[cfg(feature = "console")]
with_console_layer(&config, &mut layers);
#[cfg(feature = "error")]
with_error_layer(&config, &mut layers);
tracing_subscriber::registry().with(layers).init();
Ok(Self { config })
}
pub fn config(self) -> config::Logger {
self.config
}
}
#[cfg(feature = "env-filter")]
fn with_env_filter(
config: &config::Logger,
layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) -> Result<(), Error> {
use tracing_subscriber::EnvFilter;
const DEFAULT_ENV_FILTERS: &[&str] = &[
"ayun",
"opendal",
"sea_orm_migration",
"sqlx:query",
"tokio::task",
"tower",
"tower_http",
];
let env_layer = EnvFilter::try_from_default_env().or_else(|_| {
config.env_filter.as_ref().map_or_else(
|| {
EnvFilter::try_new(
DEFAULT_ENV_FILTERS
.iter()
.map(|target| format!("{}={}", target, config.level))
.chain(std::iter::once(format!(
"{}={}",
std::env::var("CARGO_PKG_NAME")
.unwrap_or(env!("CARGO_PKG_NAME").to_owned()),
config.level
)))
.collect::<Vec<_>>()
.join(","),
)
},
EnvFilter::try_new,
)
})?;
layers.push(Box::new(env_layer));
Ok(())
}
fn with_fmt_layer(
config: &config::Logger,
layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) -> Result<(), Error> {
let local_offset_time = OffsetTime::local_rfc_3339().expect("could not get local time offset");
let fmt_layer = fmt::Layer::default()
.with_writer(std::io::stdout.with_max_level(config.level.to_owned().into()))
.with_ansi(config.with_ansi)
.with_timer(local_offset_time)
.with_target(config.with_target)
.with_file(config.with_file)
.with_line_number(config.with_line_number)
.with_level(config.with_level)
.with_thread_ids(config.with_thread_ids)
.with_thread_names(config.with_thread_names);
let fmt_layer = match config.format {
config::Format::Compact => fmt_layer.compact().boxed(),
config::Format::Pretty => fmt_layer.pretty().boxed(),
_ => fmt_layer.boxed(),
};
layers.push(fmt_layer);
Ok(())
}
#[cfg(feature = "console")]
fn with_console_layer(
_: &config::Logger,
layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) {
layers.push(Box::new(console_subscriber::spawn()))
}
#[cfg(feature = "error")]
fn with_error_layer(_: &config::Logger, layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>) {
layers.push(Box::new(tracing_error::ErrorLayer::default()))
}