log4rust/
config.rs

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    /// This will print no stack trace
38    _None,
39    /// This is going to just print the file, line number, and collom number
40    Simple,
41    /// This is going to print a full backtrace
42    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
57/// To configure the logger you will use some different functions. <br>
58/// This is how the default configuration would look if written out:
59///
60/// ```
61/// log4rust::new()
62///     .time(Time::Local)
63///     .set_type(Log::Info)?
64///         .color(Color::TrueColor{r:0,g:255,b:255})?
65///         .console(Console::Stdout)?
66///         .backtrace(Backtrace::_None)?
67///     .set_type(Log::Warn)?
68///         .color(Color::TrueColor{r:255,g:215,b:185})?
69///         .console(Console::Stderr)?
70///         .backtrace(Backtrace::_None)?
71///     .set_type(Log::Error)?
72///         .color(Color::TrueColor{r:255,g:100,b:0})?
73///         .console(Console::Stderr)?
74///         .backtrace(Backtrace::Simple)?
75///     .set_type(Log::Fatal)?
76///         .color(Color::TrueColor{r:255,g:0,b:0})?
77///         .console(Console::Stderr)?
78///         .backtrace(Backtrace::Complex)?
79///     .save()
80///     .unwrap();
81/// ```
82///
83/// If you wanted to change something from the norm you could do
84///
85/// ```
86/// log4rust::new()
87///    .time(Time::UTC)
88///    .set_type(Log::Info)?.console(Console::_None)?
89///    .save()
90///    .unwrap();
91/// ```
92/// You can see that we only change one of the items and all the rest are the same. We also change
93/// it so that time will be saved in UTC and not in local time.
94///
95/// If you want to see some other examples look in
96/// [https://github.com/AMTitan/log4rust/tree/master/examples](https://github.com/AMTitan/log4rust/tree/master/examples)
97pub struct Config {
98    // this is an array with the length of 4 because
99    // info = 0
100    // warn = 1
101    // error = 2
102    // fatal = 3
103    #[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    // private
117    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    /// This will change the type of time that will be saved (This will save it globally and not on
157    /// a type by type basis)
158    pub fn time(mut self, time: Time) -> Self {
159        self.time = time;
160        self
161    }
162
163    /// This will change the color of a type when it is printed to the console
164    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    /// This will change the backtrace of a type when it is printed to the console
173    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    /// This will set if this type will be printed to the console or not
182    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    /// This will make it so that you can make a request every time this type goes off. You can
191    /// also have multiple of these so it will make multiple requests for every time this type
192    /// fires. This would be most useful for a webhook.
193    #[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    /// This will make it so that every time this type fires it will add it to the end of a file.
204    /// You can have multiple files that it will be added to.
205    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    /// This will set the currently selected item, this will be used so you can use the other
215    /// attributes that require a type to be set.
216    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    /// This is going to save the configuration.
230    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}