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};
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> {
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,
}
}
pub fn homemade(output: T, options: Options, modules: Vec<Box<dyn Module>>) -> Logger<T> {
Logger {
options,
timer: Timer::new(),
modules,
output,
}
}
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(_) => {}
}
}
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);
}
pub fn info<D: Display>(&mut self, msg: D) {
self.log(msg.to_string(), LogType::Info);
}
pub fn warn<D: Display>(&mut self, msg: D) {
self.log(msg.to_string(), LogType::Warning);
}
pub fn error<D: Display>(&mut self, msg: D) {
self.log(msg.to_string(), LogType::Error);
}
pub fn timer_start(&mut self, msg: &str) {
self.timer.start(msg);
}
pub fn timer_get(&self, msg: &str) -> Option<Duration> {
self.timer.get(msg)
}
pub fn timer_stop(&mut self, msg: &str) -> Option<Duration> {
self.timer.stop(msg)
}
pub fn timer_reset(&mut self, msg: &str) -> Option<Duration> {
self.timer.reset(msg)
}
pub fn timer_pause(&mut self, msg: &str) -> Option<Duration> {
self.timer.pause(msg)
}
pub fn timer_resume(&mut self, msg: &str) -> Option<Duration> {
self.timer.resume(msg)
}
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
}
}
pub fn timer_log_and_stop(&mut self, msg: &str) -> Option<Duration> {
self.timer_log(msg);
self.timer_stop(msg)
}
pub fn timer_log_and_reset(&mut self, msg: &str) -> Option<Duration> {
self.timer_log(msg);
self.timer_reset(msg)
}
}