You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
3.0 KiB

use std::{
fmt,
};
use lazy_static::lazy_static;
/// Logging mode
#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Mode
{
/// Output nothing
None,
/// Only print errors
Error,
/// Only print warnings
Warn,
/// Verbose message
Verbose,
/// Debug messages
Debug,
}
#[derive(Debug, Clone, Copy, PartialEq,Eq,Hash)]
pub enum Level
{
Debug,
Info,
Warning,
Error,
Fatal,
}
const LEVELS_FOR: &[(Mode, &[Level]); 5] = &[
(Mode::None, &[]),
(Mode::Error, &[Level::Fatal, Level::Error]),
(Mode::Warn, &[Level::Fatal, Level::Error, Level::Warning]),
(Mode::Verbose, &[Level::Fatal, Level::Error, Level::Warning, Level::Info]),
(Mode::Debug, &[Level::Fatal, Level::Error, Level::Warning, Level::Info, Level::Debug]),
];
impl Mode
{
/// Can we print this level?
#[inline]
pub fn level(&self, lv: Level) -> Option<Level>
{
if lv.mode_ok(self) {
Some(lv)
} else {
None
}
}
}
impl Level
{
/// Can we print for `mode`?
pub fn mode_ok(&self, mode: &Mode) -> bool
{
use std::collections::{HashMap, HashSet};
lazy_static! {
static ref MAP: HashMap<&'static Mode, HashSet<&'static Level>> = {
let mut m = HashMap::new();
for (key, values) in LEVELS_FOR.iter() {
let mut set = HashSet::new();
for value in values.iter() {
set.insert(value);
}
m.insert(key, set);
}
m
};
}
if let Some(values) = MAP.get(mode) {
if values.contains(self) {
true
} else {
false
}
} else {
unreachable!()
}
}
}
impl fmt::Display for Level
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Level::Debug => write!(f, "DEBUG"),
Level::Info => write!(f, "INFO"),
Level::Warning => write!(f, "WARN"),
Level::Error => write!(f, "ERROR"),
Level::Fatal => write!(f, "FATAL"),
#[allow(unreachable_patterns)]
_ => write!(f, "(unbound)"),
}
}
}
macro_rules! log {
($level:tt, $mode:expr => $format:expr) => {
{
if let Some(level) = $mode.level($crate::log::Level::$level) {
println!("{} [{}]: {}", $crate::log::timestamp(), level, $format);
true
} else {
false
};
}
};
($level:tt, $mode:expr => $format:expr, $($rest:expr),*) => {
{
if let Some(level) = $mode.level($crate::log::Level::$level) {
println!("{} [{}]: {}", $crate::log::timestamp(), level, format!($format, $($rest)*));
true
} else {
false
};
}
};
($mode:expr => $format:expr, $($rest:expr),*) => {
{
log!(Info, $mode => $format, $($rest)*);
}
};
($level:expr, $format:expr, $($rest:expr),*) => {
if let Some(level) = $level {
println!("{} [{}]: {}", $crate::log::timestamp(), level, format!($format, $($rest)*));
true
} else {
false
};
};
}
pub fn timestamp() -> String
{
use chrono::{
offset::Utc,
DateTime,
};
let time: DateTime<Utc> = std::time::SystemTime::now().into();
time.format("%Y.%m.%d %h:%M:%S").to_string()
}
//log!(Level::Debug, cmode => "Hello {}", "hi");