#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
use core as std;
use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
pub mod target;
pub mod timing;
pub mod targets;
pub struct Logger<L, C, T>
where
L: target::Target + Send + Sync + 'static,
C: AsRef<[L]> + Send + Sync + 'static,
T: timing::Timing + Send + Sync + 'static
{
pub targets: C,
pub start: T,
pub ghost: std::marker::PhantomData<L>
}
impl<L, C, T> Logger<L, C, T>
where
L: target::Target + Send + Sync + 'static,
C: AsRef<[L]> + Send + Sync + 'static,
T: timing::Timing + Send + Sync + 'static
{
pub fn new(targets: C, start: T) -> Self {
Logger { targets, start, ghost: std::marker::PhantomData }
}
pub fn start(&self) -> &T { &self.start }
pub fn start_mut(&mut self) -> &mut T { &mut self.start }
fn targets_max_level(&self) -> LevelFilter {
self.targets.as_ref().iter().fold(LevelFilter::Off, |max, target| {
if target.level() > max {
target.level().to_level_filter()
} else {
max
}
})
}
#[cfg(feature = "std")]
pub fn init_boxed(self) -> Result<(), SetLoggerError> {
let max_level = self.targets_max_level();
eprintln!(
"Initializing logger with max level of {:?} (static max level: {:?})",
max_level,
log::STATIC_MAX_LEVEL
);
log::set_max_level(max_level);
let logger = Box::new(self);
log::set_boxed_logger(logger)?;
Ok(())
}
pub fn init_static(&'static self) -> Result<(), SetLoggerError> {
let max_level = self.targets_max_level();
#[cfg(feature = "std")]
eprintln!(
"Initializing logger with max level of {:?} (static max level: {:?})",
max_level,
log::STATIC_MAX_LEVEL
);
log::set_max_level(max_level);
log::set_logger(self)?;
Ok(())
}
pub unsafe fn init_static_racy(&'static self) -> Result<(), SetLoggerError> {
let max_level = self.targets_max_level();
#[cfg(feature = "std")]
eprintln!(
"Initializing logger with max level of {:?} (static max level: {:?})",
max_level,
log::STATIC_MAX_LEVEL
);
log::set_max_level(max_level);
log::set_logger_racy(self)?;
Ok(())
}
#[cfg(feature = "std")]
fn on_error(&self, error: L::Error) {
eprintln!("{}", error);
}
#[cfg(not(feature = "std"))]
fn on_error(&self, error: L::Error) {
}
}
impl<L, C, T> Log for Logger<L, C, T>
where
L: target::Target + Send + Sync,
C: AsRef<[L]> + Send + Sync,
T: timing::Timing + Send + Sync
{
fn enabled(&self, metadata: &Metadata) -> bool {
self.targets.as_ref().iter().any(|target| target.level() >= metadata.level())
}
fn log(&self, record: &Record) {
let now = T::now();
let duration_since_start = now.duration_since(&self.start);
for target in self.targets.as_ref().iter() {
if !target.ignore(record) {
match target.write(duration_since_start, record) {
Err(e) => self.on_error(e),
Ok(_) => ()
}
}
}
}
fn flush(&self) {
for target in self.targets.as_ref().iter() {
match target.flush() {
Err(e) => self.on_error(e),
Ok(_) => ()
}
}
}
}