use crate::AsTrace;
pub use log::SetLoggerError;
use tracing_core::dispatcher;
#[derive(Debug)]
pub struct LogTracer {
ignore_crates: Box<[String]>,
}
#[derive(Debug)]
pub struct Builder {
ignore_crates: Vec<String>,
filter: log::LevelFilter,
#[cfg(all(feature = "interest-cache", feature = "std"))]
interest_cache_config: Option<crate::InterestCacheConfig>,
}
impl LogTracer {
pub fn builder() -> Builder {
Builder::default()
}
pub fn new() -> Self {
Self {
ignore_crates: Vec::new().into_boxed_slice(),
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn init_with_filter(level: log::LevelFilter) -> Result<(), SetLoggerError> {
Self::builder().with_max_level(level).init()
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn init() -> Result<(), SetLoggerError> {
Self::builder().init()
}
}
impl Default for LogTracer {
fn default() -> Self {
Self::new()
}
}
#[cfg(all(feature = "interest-cache", feature = "std"))]
use crate::interest_cache::try_cache as try_cache_interest;
#[cfg(not(all(feature = "interest-cache", feature = "std")))]
fn try_cache_interest(_: &log::Metadata<'_>, callback: impl FnOnce() -> bool) -> bool {
callback()
}
impl log::Log for LogTracer {
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
if metadata.level().as_trace() > tracing_core::LevelFilter::current() {
return false;
}
if !self.ignore_crates.is_empty() {
let target = metadata.target();
for ignored in &self.ignore_crates[..] {
if target.starts_with(ignored) {
return false;
}
}
}
try_cache_interest(metadata, || {
dispatcher::get_default(|dispatch| dispatch.enabled(&metadata.as_trace()))
})
}
fn log(&self, record: &log::Record<'_>) {
if self.enabled(record.metadata()) {
crate::dispatch_record(record);
}
}
fn flush(&self) {}
}
impl Builder {
pub fn new() -> Self {
Self::default()
}
pub fn with_max_level(self, filter: impl Into<log::LevelFilter>) -> Self {
let filter = filter.into();
Self { filter, ..self }
}
pub fn ignore_crate(mut self, name: impl Into<String>) -> Self {
self.ignore_crates.push(name.into());
self
}
pub fn ignore_all<I>(self, crates: impl IntoIterator<Item = I>) -> Self
where
I: Into<String>,
{
crates.into_iter().fold(self, Self::ignore_crate)
}
#[cfg(all(feature = "interest-cache", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "interest-cache", feature = "std"))))]
pub fn with_interest_cache(mut self, config: crate::InterestCacheConfig) -> Self {
self.interest_cache_config = Some(config);
self
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[allow(unused_mut)]
pub fn init(mut self) -> Result<(), SetLoggerError> {
#[cfg(all(feature = "interest-cache", feature = "std"))]
crate::interest_cache::configure(self.interest_cache_config.take());
let ignore_crates = self.ignore_crates.into_boxed_slice();
let logger = Box::new(LogTracer { ignore_crates });
log::set_boxed_logger(logger)?;
log::set_max_level(self.filter);
Ok(())
}
}
impl Default for Builder {
fn default() -> Self {
Self {
ignore_crates: Vec::new(),
filter: log::LevelFilter::max(),
#[cfg(all(feature = "interest-cache", feature = "std"))]
interest_cache_config: None,
}
}
}