#![allow(clippy::needless_doctest_main)]
mod builder;
mod level;
mod log_entry;
use anyhow::{Context, Error, Result};
use std::cell::{LazyCell, RefCell};
use std::collections::hash_map::IterMut;
use std::collections::{HashMap, HashSet};
use std::f32::consts;
use std::fs::{File, exists};
use std::io::Write;
use std::marker::PhantomData;
use std::module_path;
use std::ops::DerefMut;
use std::path::Path;
use std::sync::mpsc::Sender;
use std::sync::{Arc, MutexGuard, PoisonError, mpsc};
use std::thread;
use std::{fmt, fs};
pub use builder::*;
pub use level::Level;
pub use log_entry::LogEntry;
use crate::*;
pub struct Logger {
mod_path: String,
fn_name: String,
level: Level,
handlers: RefCell<HashMap<Handler, Box<dyn HandlerTrait>>>,
}
impl Logger {
pub fn builder(mod_path: &str) -> LoggerBuilder {
LoggerBuilder::create(mod_path.to_string())
}
pub fn config(&mut self, msg: &str) {
self.log(Level::CONFIG, &self.fn_name(), msg);
}
pub fn console_logger(mod_path: &str) -> Logger {
Logger::builder(mod_path).add_console_handler().build()
}
pub fn custom_logger(mod_path: &str, label: &str, custom: Box<dyn HandlerTrait>) -> Logger {
Logger::builder(mod_path)
.add_custom_handler(label, custom)
.build()
}
pub fn econsole_logger(mod_path: &str) -> Logger {
Logger::builder(mod_path).add_econsole_handler().build()
}
pub fn entering(&mut self) {
self.log(Level::FINER, &self.fn_name(), "Entry");
}
pub fn entering_with(&mut self, msg: &str) {
self.log(
Level::FINER,
&self.fn_name(),
&("Entry: (".to_string() + msg + ")"),
);
}
pub fn exiting(&mut self) {
self.log(Level::FINER, &self.fn_name(), "Return");
}
pub fn exiting_with(&mut self, msg: &str) {
self.log(
Level::FINER,
&self.fn_name(),
&("Return: (".to_string() + msg + ")"),
);
}
pub fn file_logger(mod_path: &str, filename: &str) -> Logger {
Logger::builder(mod_path).add_file_handler(filename).build()
}
pub fn fine(&mut self, msg: &str) {
self.log(Level::FINE, &self.fn_name(), msg);
}
pub fn finer(&mut self, msg: &str) {
self.log(Level::FINER, &self.fn_name(), msg);
}
pub fn finest(&mut self, msg: &str) {
self.log(Level::FINEST, &self.fn_name(), msg);
}
pub fn fn_name(&self) -> String {
self.fn_name.clone()
}
pub fn get_handler(&mut self, handler: Handler) -> Option<Box<&mut dyn HandlerTrait>> {
match self.handlers.get_mut().get_mut(&handler) {
Some(val) => Some(Box::new(&mut **val)),
None => None,
}
}
pub fn has_handler(&self, handler: Handler) -> bool {
self.handlers.borrow().contains_key(&handler)
}
pub fn info(&mut self, msg: &str) {
self.log(Level::INFO, &self.fn_name(), msg);
}
fn is_loggable(&self, level: &Level) -> bool {
*level >= self.level
}
pub fn is_logging(&self) -> bool {
self.level() != &Level::OFF
}
pub fn level(&self) -> &Level {
&self.level
}
fn _log(&mut self, entry: &mut LogEntry) {
entry.set_mod_path(self.mod_path.clone());
for handler in self.handlers.get_mut() {
handler.1.publish(entry);
}
}
fn log(&mut self, level: Level, fn_name: &str, msg: &str) {
if !self.is_loggable(&level) {
return;
}
let mut log_entry = LogEntry::create(level, fn_name.to_string(), msg.to_string());
self._log(&mut log_entry);
}
pub fn pconsole_logger(mod_path: &str) -> Logger {
Logger::builder(mod_path).add_pconsole_handler().build()
}
pub fn remove_file(filename: &str) {
let _ = fs::remove_file(filename).is_err();
}
pub fn set_fn_name(&mut self, fn_name: &str) -> &mut Self {
self.fn_name = fn_name.to_string();
self
}
pub fn set_level(&mut self, level: Level) -> &mut Self {
self.level = level;
self
}
pub fn severe(&mut self, msg: &str) {
self.log(Level::SEVERE, &self.fn_name(), msg);
}
pub fn string_logger(mod_path: &str) -> Logger {
Logger::builder(mod_path).add_string_handler().build()
}
pub fn warning(&mut self, msg: &str) {
self.log(Level::WARNING, &self.fn_name(), msg);
}
}
impl fmt::Display for Logger {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = String::new();
for elem in self.handlers.borrow().iter() {
let s = format!("{}: {}\n", elem.0, elem.1);
buf.push_str(&s);
}
writeln!(
f,
"{}::{} - [{}]\n\n{}",
self.mod_path, self.fn_name, self.level, buf
)
}
}
#[cfg(test)]
mod tests;