xuko 0.10.0

Rust utility library
Documentation
//! Simple logger for [`log`]

use log::{Level, LevelFilter, Log};
use std::sync::OnceLock;

static LOGGER: OnceLock<Logger> = OnceLock::new();

/// Simple logger
pub struct Logger {
    /// Maximum level allowed by the logger
    pub max_level: LevelFilter,
}

impl Logger {
    /// Create a [`Logger`] with default options
    pub fn new() -> Self {
        Self {
            max_level: LevelFilter::Info,
        }
    }
}

impl Default for Logger {
    fn default() -> Self {
        Self::new()
    }
}

impl Log for Logger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level().to_level_filter() <= self.max_level
    }

    fn log(&self, record: &log::Record) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let level_string = match record.level() {
            Level::Error => "ERROR",
            Level::Warn => "WARN",
            Level::Info => "INFO",
            Level::Debug => "DEBUG",
            Level::Trace => "TRACE",
        };

        let target_string = match (record.file(), record.line()) {
            (Some(file), Some(line)) => format!(" [{} {file}:{line}]", record.target()),
            _ => "".to_owned(),
        };

        let msg = format!("[{level_string:5}]{} {}", target_string, record.args());

        eprintln!("{msg}");
    }

    fn flush(&self) {}
}

/// Initializes the [`log`] to use `logger`.
pub fn init(logger: Logger) {
    if LOGGER.get().is_some() {
        return;
    }
    let l = LOGGER.get_or_init(|| {
        log::set_max_level(logger.max_level);
        logger
    });
    log::set_logger(l).unwrap();
}

/// Builder for a [`Logger`]
pub struct Builder {
    logger: Logger,
}

impl Builder {
    /// Create a [`Builder`]
    pub fn new() -> Self {
        Self {
            logger: Logger::new(),
        }
    }

    /// Construct the [`Logger`]
    pub fn build(self) -> Logger {
        self.logger
    }

    /// Set the [`Logger::max_level`] property.
    pub fn max_level(mut self, max_level: LevelFilter) -> Self {
        self.logger.max_level = max_level;
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic() {
        init(Builder::new().max_level(LevelFilter::Trace).build());
        log::logger();

        log::info!("hello world");
        log::warn!("this is cool");
        log::error!("this is an error");
        log::trace!("trace");
    }
}