parent
92d88ce74a
commit
55b71a10dc
@ -1,519 +0,0 @@
|
||||
//! Global logging state
|
||||
use super::util::*;
|
||||
|
||||
use std::{
|
||||
fmt::{
|
||||
self,
|
||||
Display,
|
||||
},
|
||||
io::{
|
||||
self,
|
||||
Write,
|
||||
},
|
||||
borrow::Borrow,
|
||||
sync::{RwLock},
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
/// Print local time by default
|
||||
const DEFAULT_USE_LOCAL_TIME: bool = crate::config::build::log::DEFAULT_LOCAL_TIME;
|
||||
|
||||
/// Logging level
|
||||
#[derive(PartialEq,Copy,Eq,Debug,Clone,Hash,Ord,PartialOrd)]
|
||||
pub enum Level
|
||||
{
|
||||
Silent,
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
}
|
||||
|
||||
/// Contains backtrace info from where the log macro was invoked
|
||||
#[derive(Debug)]
|
||||
pub struct Trace
|
||||
{
|
||||
line: Option<usize>,
|
||||
file: Option<&'static str>,
|
||||
column: Option<usize>,
|
||||
|
||||
display: Opaque<RwLock<Option<String>>>,
|
||||
}
|
||||
|
||||
impl Clone for Trace
|
||||
{
|
||||
#[inline]
|
||||
fn clone(&self) -> Self
|
||||
{
|
||||
Self {
|
||||
line: self.line.clone(),
|
||||
file: self.file.clone(),
|
||||
column: self.column.clone(),
|
||||
|
||||
display: Opaque::new(RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for Trace
|
||||
{
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H)
|
||||
{
|
||||
self.line.hash(state);
|
||||
self.file.hash(state);
|
||||
self.column.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::PartialEq for Trace
|
||||
{
|
||||
fn eq(&self, other: &Self)->bool
|
||||
{
|
||||
self.line == other.line &&
|
||||
self.file == other.file &&
|
||||
self.column == other.column
|
||||
}
|
||||
}
|
||||
|
||||
impl Trace
|
||||
{
|
||||
/// Create a new `Trace` manually. Generally not desireable, use `get_trace!()` instead.
|
||||
pub fn new(file: Option<&'static str>, line: Option<u32>, column: Option<u32>) -> Self
|
||||
{
|
||||
use std::convert::TryInto;
|
||||
let this = Self{
|
||||
file,
|
||||
line: line.and_then(|x| x.try_into().ok()),
|
||||
column: column.and_then(|x| x.try_into().ok()),
|
||||
display: Opaque::new(RwLock::new(None)),
|
||||
};
|
||||
this
|
||||
}
|
||||
|
||||
fn genstring(&self) -> Result<String, fmt::Error>
|
||||
{
|
||||
let mut out = String::new();
|
||||
use std::fmt::Write as FmtWrite;
|
||||
|
||||
write!(out, "{}", self.file.unwrap_or("(unbound)"))?;
|
||||
if let Some(line) = self.line {
|
||||
write!(&mut out, ":{}", line)?;
|
||||
} else {
|
||||
write!(&mut out, ":?")?;
|
||||
}
|
||||
if let Some(column) = self.column {
|
||||
write!(&mut out, ":{}", column)?;
|
||||
} else {
|
||||
write!(&mut out, ":?")?;
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Trace
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
{
|
||||
let read = self.display.read().expect("Poisoned");
|
||||
if let Some(opt) = read.as_ref()
|
||||
{
|
||||
write!(f, "{}", opt)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let out = self.genstring()?;
|
||||
|
||||
write!(f, "{}", out)?;
|
||||
|
||||
let mut write = self.display.write().expect("Poisoned");
|
||||
*write = Some(out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Default for Trace
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self{
|
||||
line:None,
|
||||
file:None,
|
||||
column:None,
|
||||
|
||||
display: Opaque::new(RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a source code trace of the current file, line and column.
|
||||
#[macro_export] macro_rules! get_trace
|
||||
{
|
||||
() => {
|
||||
$crate::log::Trace::new(Some(file!()), Some(line!()), Some(column!()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Append this trait to allow you to
|
||||
pub trait AsLevel: fmt::Display + Borrow<Level>{
|
||||
/// Used for derived levels
|
||||
fn prefix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "{}/", Borrow::<Level>::borrow(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsLevel for Level{
|
||||
#[inline] fn prefix(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result{Ok(())}
|
||||
}
|
||||
impl AsLevel for &Level{
|
||||
#[inline] fn prefix(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result{Ok(())}
|
||||
}
|
||||
|
||||
impl Default for Level
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Level
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
return Level::Debug;
|
||||
#[cfg(not(debug_assertions))]
|
||||
return Level::Warn;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Level
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
use recolored::Colorize;
|
||||
write!(f, "{}", match &self {
|
||||
Self::Silent => "Fatal".bright_red().bold(),
|
||||
Self::Error => "Error".red(),
|
||||
Self::Warn => "Warning".yellow(),
|
||||
Self::Info => "Info".normal(),
|
||||
Self::Debug => "Debug".dimmed(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A logger that prints to stdout and stderr idk.
|
||||
/// # TODO
|
||||
/// Make this a trait and have variants that print to files and such
|
||||
#[derive(Debug)]
|
||||
pub struct Logger
|
||||
{
|
||||
level: Level,
|
||||
title: String,
|
||||
use_local_time: bool,
|
||||
}
|
||||
|
||||
static INSTANCE: OnceCell<Logger> = OnceCell::new();
|
||||
|
||||
impl Logger
|
||||
{
|
||||
pub fn new(level: Level) -> Self
|
||||
{
|
||||
Self {
|
||||
level,
|
||||
title: String::new(),
|
||||
use_local_time: DEFAULT_USE_LOCAL_TIME,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn global() -> &'static Logger
|
||||
{
|
||||
INSTANCE.get().expect("[logger] uninitialised")
|
||||
}
|
||||
|
||||
|
||||
fn initialise(level: Level) -> &'static Logger
|
||||
{
|
||||
INSTANCE.set(Logger::new(level)).expect("[logger] already initialised");
|
||||
Logger::global()
|
||||
}
|
||||
|
||||
pub fn println<W,L,D,T>(&self, mut to: W, level: L, what: D, trace: T) -> io::Result<()>
|
||||
where W: Write,
|
||||
L: AsLevel,
|
||||
D: Display,
|
||||
T: Borrow<Trace>
|
||||
{
|
||||
//lol
|
||||
enum Date {
|
||||
Local(chrono::DateTime<chrono::offset::Local>),
|
||||
Utc(chrono::DateTime<chrono::offset::Utc>),
|
||||
}
|
||||
impl std::fmt::Display for Date
|
||||
{
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
match self {
|
||||
Self::Local(l) => write!(f, "{}", l.format("%Y-%m-%d %H:%M:%S %Z")),
|
||||
Self::Utc(l) => write!(f, "{}", l.format("%Y-%m-%d %H:%M:%S %Z")),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<chrono::DateTime<chrono::offset::Local>> for Date
|
||||
{
|
||||
#[inline]
|
||||
fn from(from: chrono::DateTime<chrono::offset::Local>) -> Self
|
||||
{
|
||||
Self::Local(from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<chrono::DateTime<chrono::offset::Utc>> for Date
|
||||
{
|
||||
#[inline]
|
||||
fn from(from: chrono::DateTime<chrono::offset::Utc>) -> Self
|
||||
{
|
||||
Self::Utc(from)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if &self.level >= level.borrow() {
|
||||
let now: Date = if self.use_local_time {
|
||||
chrono::offset::Local::now().into()
|
||||
} else {
|
||||
chrono::offset::Utc::now().into()
|
||||
};
|
||||
|
||||
write!(to, "{} ", now)?;
|
||||
if self.title.len() > 0 {
|
||||
write!(to, " <{}>\t", self.title)?;
|
||||
} else {
|
||||
write!(to, " <{}>\t", trace.borrow())?;
|
||||
}
|
||||
write!(to," [")?;
|
||||
|
||||
struct Prefix<'a,L: AsLevel>(&'a L);
|
||||
|
||||
impl<'a,L: AsLevel> std::fmt::Display for Prefix<'a, L>
|
||||
{
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
self.0.prefix(f)
|
||||
}
|
||||
}
|
||||
|
||||
write!(to, "{}", Prefix(&level))?; //what a mess...
|
||||
write!(to, "{}", level)?;
|
||||
write!(to, "]: ")?;
|
||||
writeln!(to, "{}", what)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(any(debug_assertions,feature="debug_logger"))]
|
||||
#[macro_export] macro_rules! debug {
|
||||
($obj:expr) => {
|
||||
{
|
||||
let stdout = std::io::stdout();
|
||||
let stdout = stdout.lock();
|
||||
$crate::log::Logger::global().println(stdout, $crate::log::Level::Debug, $obj, get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
debug!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(any(debug_assertions,feature="debug_logger")))]
|
||||
#[macro_export] macro_rules! debug {
|
||||
($obj:expr) => {{}};
|
||||
($fmt:literal, $($args:expr),*) => {{}};
|
||||
}
|
||||
|
||||
|
||||
#[cfg(any(debug_assertions,feature="debug_logger"))]
|
||||
#[macro_export] macro_rules! status {
|
||||
($obj:expr) => {
|
||||
{
|
||||
struct Status;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
fmt,
|
||||
};
|
||||
impl Borrow<$crate::log::Level> for Status {
|
||||
fn borrow(&self) -> &$crate::log::Level
|
||||
{
|
||||
&$crate::log::Level::Debug
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Status
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
use recolored::Colorize;
|
||||
write!(f, "{}", "Status".blue())
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::log::AsLevel for Status{}
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let stdout = stdout.lock();
|
||||
$crate::log::Logger::global().println(stdout, Status, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
status!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(any(debug_assertions,feature="debug_logger")))]
|
||||
#[macro_export] macro_rules! status {
|
||||
($obj:expr) => {{}};
|
||||
($fmt:literal, $($args:expr),*) => {{}};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! info {
|
||||
($obj:expr) => {
|
||||
{
|
||||
let stdout = std::io::stdout();
|
||||
let stdout = stdout.lock();
|
||||
$crate::log::Logger::global().println(stdout, $crate::log::Level::Info, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::info!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! important {
|
||||
($obj:expr) => {
|
||||
{
|
||||
struct Important;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
fmt,
|
||||
};
|
||||
impl Borrow<$crate::log::Level> for Important {
|
||||
fn borrow(&self) -> &$crate::log::Level
|
||||
{
|
||||
&$crate::log::Level::Info
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Important
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
use recolored::Colorize;
|
||||
write!(f, "{}", "Important".bright_blue())
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::log::AsLevel for Important{}
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let stdout = stdout.lock();
|
||||
$crate::log::Logger::global().println(stdout, Important, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::important!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[macro_export] macro_rules! warn {
|
||||
($obj:expr) => {
|
||||
{
|
||||
let stderr = std::io::stderr();
|
||||
let stderr = stderr.lock();
|
||||
$crate::log::Logger::global().println(stderr, $crate::log::Level::Warn, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::warn!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[macro_export] macro_rules! dangerous {
|
||||
($obj:expr) => {
|
||||
{
|
||||
struct Dangerous;
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
fmt,
|
||||
};
|
||||
impl Borrow<$crate::log::Level> for Dangerous {
|
||||
fn borrow(&self) -> &$crate::log::Level
|
||||
{
|
||||
&$crate::log::Level::Warn
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Dangerous
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
use recolored::Colorize;
|
||||
write!(f, "{}", "Dangerous".bright_yellow())
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::log::AsLevel for Dangerous{}
|
||||
|
||||
let stderr = std::io::stderr();
|
||||
let stderr = stderr.lock();
|
||||
$crate::log::Logger::global().println(stderr, Dangerous, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::dangerous!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! error {
|
||||
($obj:expr) => {
|
||||
{
|
||||
let stderr = std::io::stderr();
|
||||
let stderr = stderr.lock();
|
||||
$crate::log::Logger::global().println(stderr, $crate::log::Level::Error, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::error!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! fatal {
|
||||
($obj:expr) => {
|
||||
{
|
||||
let stdout = std::io::stdout();
|
||||
let stdout = stdout.lock();
|
||||
$crate::log::Logger::global().println(stdout, $crate::log::Level::Silent, $obj, $crate::get_trace!()).expect("i/o error");
|
||||
|
||||
std::process::exit(-1)
|
||||
}
|
||||
};
|
||||
($fmt:literal, $($args:expr),*) => {
|
||||
$crate::fatal!(format!($fmt, $($args,)*));
|
||||
};
|
||||
}
|
||||
|
||||
/// Initialise the global logger instance. If logging macros are called before this, they will panic.
|
||||
#[inline]
|
||||
pub fn init(level: Level)
|
||||
{
|
||||
Logger::initialise(level);
|
||||
}
|
||||
|
||||
/// The global logger's level
|
||||
#[inline]
|
||||
pub fn level() -> &'static Level
|
||||
{
|
||||
&Logger::global().level
|
||||
}
|
Loading…
Reference in new issue