rusty-logger 0.3.0

A modular and simple logger for rust
Documentation
use crate::modules::{self, Module};
use crate::options::Options;
use crate::timer::Timer;
use crate::types::{LogType, TimeUnit};
use std::{fmt::Display, io::stderr, time::Duration};

/// A modular and powerful logger
///
/// # Example
///
/// ```
/// use rusty_logger::Logger;
/// use rusty_logger::types;
///
/// let mut logger = Logger::new("EXAMPLE", std::io::stdout());
///
/// logger.options.time_unit = types::TimeUnit::Nanoseconds;
///
/// logger.info("We will be timing a for loop");
///
/// logger.timer_start("for loop");
///
/// for i in 0..1000 {
///     // Do something...
/// }
///
/// logger.timer_log_and_stop("for loop");
///
/// logger.info("The for loop ended successfully");
/// ```
pub struct Logger<T: std::io::Write> {
    pub options: Options,
    timer: Timer,
    modules: Vec<Box<dyn Module>>,
    output: T,
}

pub struct LogMessage<'a> {
    pub content: &'a str,
    pub msg_type: LogType,
    pub options: &'a Options,
}

impl<T: std::io::Write> Logger<T> {
    /// Creates a new Logger with default values and the given name
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.info("This is a new logger named 'name' !");
    /// ```
    pub fn new(s: &str, output: T) -> Self {
        let modules: Vec<Box<dyn Module>> = vec![
            Box::new(modules::Name {}),
            Box::new(modules::Time {}),
            Box::new(modules::Type {}),
        ];
        Logger {
            options: Options::new(s),
            timer: Timer::new(),
            modules,
            output,
        }
    }

    /// Creates a new Logger with custom options and modules
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::{
    ///     Logger,
    ///     Module,
    ///     Options,
    ///     modules,
    /// };
    ///
    /// let options = Options::new("homemade logger");
    ///
    /// let modules: Vec<Box<dyn Module>> = vec!(
    ///     Box::new(modules::Name{}),
    ///     Box::new(modules::Time{}),
    ///     Box::new(modules::Type{})
    /// );
    ///
    /// let mut logger = Logger::homemade(std::io::stdout(), options, modules);
    ///
    /// logger.info("This is a new logger named 'name' which has 'options' as its options !");
    /// ```
    pub fn homemade(output: T, options: Options, modules: Vec<Box<dyn Module>>) -> Logger<T> {
        Logger {
            options,
            timer: Timer::new(),
            modules,
            output,
        }
    }

    /// Formats the message with the current logger options
    /// and then prints it. It is a private function and is
    /// only used by the other internal functions to print
    /// the message.
    ///
    /// It goes through the options of the logger it is
    /// called on and formats the message accordingly.
    fn log(&mut self, msg: String, msg_type: LogType) {
        let mut output = String::new();

        let lm = LogMessage {
            content: &msg[..],
            msg_type,
            options: &self.options,
        };

        self.modules.iter_mut().for_each(|module| {
            output.push_str(&module.print(&lm));
        });

        match writeln!(self.output, "{}: {}", output, msg) {
            std::result::Result::Err(err) => Logger::static_log(err, LogType::Error, stderr()),
            std::result::Result::Ok(_) => {}
        }
    }

    /// Static implementation for the log function
    ///
    /// Mainly used to print internal error messages
    /// but can also be used by an end user
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::{Logger, types::LogType};
    ///
    /// Logger::static_log("Printing on the fly", LogType::Info, std::io::stdout());
    /// ```
    pub fn static_log<D: Display>(msg: D, msg_type: LogType, output: T) {
        let mut logger = Logger::new("STATIC", output);
        logger.log(msg.to_string(), msg_type);
    }

    /// Logs the given message to the output
    /// as an information
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.info("Here is some information I want to log");
    /// ```
    pub fn info<D: Display>(&mut self, msg: D) {
        self.log(msg.to_string(), LogType::Info);
    }

    /// Logs the given message to the output
    /// as a warning
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.warn("Here is a warning");
    /// ```
    pub fn warn<D: Display>(&mut self, msg: D) {
        self.log(msg.to_string(), LogType::Warning);
    }

    /// Logs the given message to the output
    /// as an error
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.info("Some error happened");
    /// ```
    pub fn error<D: Display>(&mut self, msg: D) {
        self.log(msg.to_string(), LogType::Error);
    }

    /// Starts a new timer with the given name
    /// and the actual time
    pub fn timer_start(&mut self, msg: &str) {
        self.timer.start(msg);
    }

    /// Gets the duration from when the timer
    /// with the given name was started
    pub fn timer_get(&self, msg: &str) -> Option<Duration> {
        self.timer.get(msg)
    }

    /// Stops the timer with the given name
    /// and returns it as a duration
    pub fn timer_stop(&mut self, msg: &str) -> Option<Duration> {
        self.timer.stop(msg)
    }

    /// Resets the timer with the given name
    /// and returns the duration of the timer
    /// before being reset as a duration
    pub fn timer_reset(&mut self, msg: &str) -> Option<Duration> {
        self.timer.reset(msg)
    }

    /// Pauses the timer with the given name
    /// and returns the duration of the timer
    /// before pausing it as a duration
    pub fn timer_pause(&mut self, msg: &str) -> Option<Duration> {
        self.timer.pause(msg)
    }

    /// Resumes the timer with the given name
    pub fn timer_resume(&mut self, msg: &str) -> Option<Duration> {
        self.timer.resume(msg)
    }

    /// Logs the time elapsed between the
    /// start/reset of the timer and now
    /// **without** reseting it
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.timer_start("new_timer");
    ///
    /// std::thread::sleep(std::time::Duration::from_millis(1));
    ///
    /// logger.timer_log("new_timer");
    /// ```
    pub fn timer_log(&mut self, msg: &str) -> Option<Duration> {
        if let Some(time) = self.timer.get(msg) {
            match self.options.time_unit {
                TimeUnit::Nanoseconds => {
                    self.log(format!("{} - {}ns", msg, time.as_nanos()), LogType::Time);
                }
                TimeUnit::Microseconds => {
                    self.log(format!("{} - {}μs", msg, time.as_micros()), LogType::Time);
                }
                TimeUnit::Milliseconds => {
                    self.log(format!("{} - {}ms", msg, time.as_millis()), LogType::Time);
                }
            }
            Some(time)
        } else {
            Logger::static_log(msg, LogType::Error, stderr());
            None
        }
    }

    /// Logs the time elapsed between the
    /// start/reset of the timer and now
    /// and then stops it
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.timer_start("new_timer");
    ///
    /// std::thread::sleep(std::time::Duration::from_millis(1));
    ///
    /// logger.timer_log_and_stop("new_timer");
    /// ```
    pub fn timer_log_and_stop(&mut self, msg: &str) -> Option<Duration> {
        self.timer_log(msg);
        self.timer_stop(msg)
    }

    /// Logs the time elapsed between the
    /// start/reset of the timer and now
    /// and then resets it
    ///
    /// # Example
    ///
    /// ```
    /// use rusty_logger::Logger;
    ///
    /// let mut logger = Logger::new("name", std::io::stdout());
    ///
    /// logger.timer_start("new_timer");
    ///
    /// std::thread::sleep(std::time::Duration::from_millis(1));
    ///
    /// logger.timer_log_and_reset("new_timer");
    ///
    /// std::thread::sleep(std::time::Duration::from_millis(1));
    ///
    /// logger.timer_log_and_stop("new_timer");
    /// ```
    pub fn timer_log_and_reset(&mut self, msg: &str) -> Option<Duration> {
        self.timer_log(msg);
        self.timer_reset(msg)
    }
}