use colored::Color;
use lazy_static::lazy_static;
use std::io::{Error, ErrorKind};
use std::sync::{Mutex, MutexGuard, PoisonError};
use std::fmt;
#[cfg(feature = "web")]
use ureq::Request;
lazy_static! {
#[doc(hidden)]
pub static ref CONFIG: Mutex<Config> = Mutex::new(new());
}
#[derive(Clone)]
pub enum Log {
Info,
Warn,
Error,
Fatal,
#[doc(hidden)]
_None,
}
impl fmt::Debug for Log {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Log::Info => write!(f, "info"),
Log::Warn => write!(f, "warn"),
Log::Error => write!(f, "error"),
Log::Fatal => write!(f, "fatal"),
Log::_None => write!(f, ""),
}
}
}
pub enum Backtrace {
_None,
Simple,
Complex,
}
#[derive(PartialEq)]
pub enum Time {
UTC,
Local,
}
pub enum Console {
_None,
Stdout,
Stderr,
}
pub struct Config {
#[doc(hidden)]
pub time: Time,
#[doc(hidden)]
pub color: [Color; 4],
#[doc(hidden)]
pub console: [Console; 4],
#[doc(hidden)]
#[cfg(feature = "web")]
pub web: [Vec<(Request, String)>; 4],
#[doc(hidden)]
pub file: [Vec<String>; 4],
#[doc(hidden)]
pub backtrace: [Backtrace; 4],
working_on: Log,
}
pub fn new() -> Config {
Config {
time: Time::Local,
color: [
Color::TrueColor {
r: 0,
g: 255,
b: 255,
},
Color::TrueColor {
r: 255,
g: 215,
b: 185,
},
Color::TrueColor {
r: 255,
g: 100,
b: 0,
},
Color::TrueColor { r: 255, g: 0, b: 0 },
],
console: [Console::Stdout, Console::Stderr, Console::Stderr, Console::Stderr],
#[cfg(feature = "web")]
web: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
file: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
backtrace: [
Backtrace::_None,
Backtrace::_None,
Backtrace::Simple,
Backtrace::Complex,
],
working_on: Log::_None,
}
}
impl Config {
pub fn time(mut self, time: Time) -> Self {
self.time = time;
self
}
pub fn color(mut self, color: Color) -> Result<Self, Error> {
self.color[index(
self.working_on.clone(),
"You need to set a log type before you can set the color",
)?] = color;
Ok(self)
}
pub fn backtrace(mut self, backtrace: Backtrace) -> Result<Self, Error> {
self.backtrace[index(
self.working_on.clone(),
"You need to set a log type before you can set the backtrace",
)?] = backtrace;
Ok(self)
}
pub fn console(mut self, console: Console) -> Result<Self, Error> {
self.console[index(
self.working_on.clone(),
"You need to set a log type before you can set if it goes to the terminal",
)?] = console;
Ok(self)
}
#[cfg(feature = "web")]
pub fn web(mut self, format: &str, request: Request) -> Result<Self, Error> {
self.web[index(
self.working_on.clone(),
"You need to set a log type before you can set where it should be sent to",
)?]
.push((request, format.to_string()));
Ok(self)
}
pub fn file(mut self, file: &str) -> Result<Self, Error> {
self.file[index(
self.working_on.clone(),
"You need to set a log type before you can set where it should be sent to",
)?]
.push(file.to_string());
Ok(self)
}
pub fn set_type(mut self, log: Log) -> Result<Self, Error> {
match log {
Log::_None => {
return Err(Error::new(
ErrorKind::Other,
"You can not set the current log type to none",
))
}
_ => self.working_on = log,
}
Ok(self)
}
pub fn save(self) -> Result<(), PoisonError<MutexGuard<'static, Config>>> {
let mut config = CONFIG.lock()?;
*config = self;
Ok(())
}
}
fn index(working_on: Log, if_none: &str) -> Result<usize, Error> {
match working_on {
Log::Info => Ok(0),
Log::Warn => Ok(1),
Log::Error => Ok(2),
Log::Fatal => Ok(3),
Log::_None => return Err(Error::new(ErrorKind::Other, if_none)),
}
}