1use colored::Color;
2use lazy_static::lazy_static;
3use std::io::{Error, ErrorKind};
4use std::sync::{Mutex, MutexGuard, PoisonError};
5use std::fmt;
6#[cfg(feature = "web")]
7use ureq::Request;
8
9lazy_static! {
10 #[doc(hidden)]
11 pub static ref CONFIG: Mutex<Config> = Mutex::new(new());
12}
13
14#[derive(Clone)]
15pub enum Log {
16 Info,
17 Warn,
18 Error,
19 Fatal,
20 #[doc(hidden)]
21 _None,
22}
23
24impl fmt::Debug for Log {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match *self {
27 Log::Info => write!(f, "info"),
28 Log::Warn => write!(f, "warn"),
29 Log::Error => write!(f, "error"),
30 Log::Fatal => write!(f, "fatal"),
31 Log::_None => write!(f, ""),
32 }
33 }
34}
35
36pub enum Backtrace {
37 _None,
39 Simple,
41 Complex,
43}
44
45#[derive(PartialEq)]
46pub enum Time {
47 UTC,
48 Local,
49}
50
51pub enum Console {
52 _None,
53 Stdout,
54 Stderr,
55}
56
57pub struct Config {
98 #[doc(hidden)]
104 pub time: Time,
105 #[doc(hidden)]
106 pub color: [Color; 4],
107 #[doc(hidden)]
108 pub console: [Console; 4],
109 #[doc(hidden)]
110 #[cfg(feature = "web")]
111 pub web: [Vec<(Request, String)>; 4],
112 #[doc(hidden)]
113 pub file: [Vec<String>; 4],
114 #[doc(hidden)]
115 pub backtrace: [Backtrace; 4],
116 working_on: Log,
118}
119
120pub fn new() -> Config {
121 Config {
122 time: Time::Local,
123 color: [
124 Color::TrueColor {
125 r: 0,
126 g: 255,
127 b: 255,
128 },
129 Color::TrueColor {
130 r: 255,
131 g: 215,
132 b: 185,
133 },
134 Color::TrueColor {
135 r: 255,
136 g: 100,
137 b: 0,
138 },
139 Color::TrueColor { r: 255, g: 0, b: 0 },
140 ],
141 console: [Console::Stdout, Console::Stderr, Console::Stderr, Console::Stderr],
142 #[cfg(feature = "web")]
143 web: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
144 file: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
145 backtrace: [
146 Backtrace::_None,
147 Backtrace::_None,
148 Backtrace::Simple,
149 Backtrace::Complex,
150 ],
151 working_on: Log::_None,
152 }
153}
154
155impl Config {
156 pub fn time(mut self, time: Time) -> Self {
159 self.time = time;
160 self
161 }
162
163 pub fn color(mut self, color: Color) -> Result<Self, Error> {
165 self.color[index(
166 self.working_on.clone(),
167 "You need to set a log type before you can set the color",
168 )?] = color;
169 Ok(self)
170 }
171
172 pub fn backtrace(mut self, backtrace: Backtrace) -> Result<Self, Error> {
174 self.backtrace[index(
175 self.working_on.clone(),
176 "You need to set a log type before you can set the backtrace",
177 )?] = backtrace;
178 Ok(self)
179 }
180
181 pub fn console(mut self, console: Console) -> Result<Self, Error> {
183 self.console[index(
184 self.working_on.clone(),
185 "You need to set a log type before you can set if it goes to the terminal",
186 )?] = console;
187 Ok(self)
188 }
189
190 #[cfg(feature = "web")]
194 pub fn web(mut self, format: &str, request: Request) -> Result<Self, Error> {
195 self.web[index(
196 self.working_on.clone(),
197 "You need to set a log type before you can set where it should be sent to",
198 )?]
199 .push((request, format.to_string()));
200 Ok(self)
201 }
202
203 pub fn file(mut self, file: &str) -> Result<Self, Error> {
206 self.file[index(
207 self.working_on.clone(),
208 "You need to set a log type before you can set where it should be sent to",
209 )?]
210 .push(file.to_string());
211 Ok(self)
212 }
213
214 pub fn set_type(mut self, log: Log) -> Result<Self, Error> {
217 match log {
218 Log::_None => {
219 return Err(Error::new(
220 ErrorKind::Other,
221 "You can not set the current log type to none",
222 ))
223 }
224 _ => self.working_on = log,
225 }
226 Ok(self)
227 }
228
229 pub fn save(self) -> Result<(), PoisonError<MutexGuard<'static, Config>>> {
231 let mut config = CONFIG.lock()?;
232 *config = self;
233 Ok(())
234 }
235}
236
237fn index(working_on: Log, if_none: &str) -> Result<usize, Error> {
238 match working_on {
239 Log::Info => Ok(0),
240 Log::Warn => Ok(1),
241 Log::Error => Ok(2),
242 Log::Fatal => Ok(3),
243 Log::_None => return Err(Error::new(ErrorKind::Other, if_none)),
244 }
245}