logging/
lib.rs

1//!
2//! A logging fascility inspired by the python logging framework.
3//!
4//! This library implements named herachical loggers which have message
5//! handlers associated with them.
6//!
7//! The framework is  intended more for people who want to set log levels for there application
8//! without the need to recompile the software.
9//!
10//! ## features
11//!
12//! + Thread safe.
13//! + Easy to extend.
14//! + Log handlers can be added and removed at runtime.
15//! + Log levels can be changed at runtime.
16//!
17//! ## behavior
18//!
19//! + Via default there is no log handler added.
20//! + The default log level of all loggers is `DEFAULT`.
21//! + Log messages bubble up to their parents and will be logged by all intermediate handlers.
22//!
23//! ## usage
24//!
25//! ```rust
26//! extern crate logging;
27//!
28//! use std::sync::Arc;
29//!
30//! struct MyOwnHandler {}
31//!
32//! impl logging::Handler for MyOwnHandler {
33//!   fn emit(&self, msg: &logging::Message) {
34//!     print!("{:7} | {}", msg.name, msg.msg);
35//!   }
36//! }
37//!
38//! fn main() {
39//!   // you will see nothing, because no handler added yet
40//!   logging::debug("app started");
41//!
42//!   logging::root().add_handler(Arc::new(Box::new(MyOwnHandler {})));
43//!
44//!   let log = logging::get("myapp");
45//!   log.add_handler(logging::ConsoleHandler::new());
46//!
47//!   // will be printed by both handlers
48//!   log.info("created".to_owned());
49//!   {
50//!     let sub_log = logging::get("myapp.special");
51//!     sub_log.debug("some other stuff");
52//!   }
53//!
54//!   log.level = logging::Level::WARN;
55//!   // will not be printed by the handler of `myapp`.
56//!   log.info("unly plain not in color");
57//! }
58//! ```
59//!
60extern crate ansi_term;
61
62use ansi_term::Colour;
63use std::collections::HashMap;
64use std::fs::File;
65use std::io::{self, Write};
66use std::sync::{Arc, RwLock};
67use std::time::{SystemTime, UNIX_EPOCH};
68
69///
70/// The aviable logging levels.
71///
72#[derive(PartialEq, PartialOrd, Clone, Copy)]
73pub enum Level {
74    /// For debuging and tracing information.
75    DEBUG,
76    /// For general informations.
77    INFO,
78    /// Warning about non critical male behaviour.
79    WARN,
80    /// This is when something went very wrong.
81    ERROR,
82    /// The sh*t hits the fan, you possible should run for your live.
83    FATAL,
84    /// Nothing will be logged.
85    NONE,
86}
87
88///
89/// A message to be logged.
90///
91pub struct Message {
92    /// The level of the message.
93    level: Level,
94    /// The full name of the logger.
95    name: String,
96    /// The timestamp of creation.
97    created: SystemTime,
98    /// The message string itself.
99    msg: String,
100}
101
102
103///
104/// Handels an emitted message.
105///
106pub trait Handler: Send + Sync {
107    /// Actually do something with the message.
108    fn emit(&self, message: &Message);
109}
110
111
112///
113/// Colorfull console logging
114///
115/// + uses: https://github.com/ogham/rust-ansi-term
116///
117pub struct ConsoleHandler {}
118
119impl ConsoleHandler {
120    pub fn new() -> Arc<Box<Handler>> {
121        Arc::new(Box::new(ConsoleHandler {}))
122    }
123}
124
125
126impl Handler for ConsoleHandler {
127    fn emit(&self, message: &Message) {
128        let data = match message.level {
129            Level::DEBUG => Colour::Cyan.paint(format!("{} | {}\n", message.name, message.msg)),
130            Level::INFO => Colour::Green.paint(format!("{} | {}\n", message.name, message.msg)),
131            Level::WARN => Colour::Yellow.paint(format!("{} | {}\n", message.name, message.msg)),
132            Level::ERROR => Colour::Red.paint(format!("{} | {}\n", message.name, message.msg)),
133            Level::FATAL => Colour::Red.paint(format!("{} | {}\n", message.name, message.msg)),
134            Level::NONE => Colour::White.paint(""),
135        };
136
137        let stdout = io::stdout();
138        let mut handle = stdout.lock();
139
140        handle.write(data.to_string().as_bytes()).unwrap();
141        handle.flush().unwrap();
142    }
143}
144
145
146///
147/// Logging to a file
148///
149/// ```
150/// extern crate logging;
151///
152/// fn main() {
153///   let handler = logging::FileHandler::new("my.log");
154///   logging::root().add_handler(handler);
155/// }
156///
157pub struct FileHandler {
158    out: Arc<RwLock<File>>,
159}
160
161
162impl FileHandler {
163    pub fn new(filename: &str) -> Arc<Box<Handler>> {
164        Arc::new(Box::new(FileHandler {
165            out: Arc::new(RwLock::new(File::create(filename).unwrap())),
166        }))
167    }
168}
169
170
171impl Handler for FileHandler {
172    fn emit(&self, message: &Message) {
173        let dur = message.created.duration_since(UNIX_EPOCH).unwrap();
174
175        let data = match message.level {
176            Level::DEBUG => {
177                format!(
178                    "{:9}.{:0.09} | DEBUG | {:15} | {}\n",
179                    dur.as_secs(),
180                    dur.subsec_nanos(),
181                    message.name,
182                    message.msg
183                )
184            }
185            Level::INFO => {
186                format!(
187                    "{:9}.{:0.09} |  INFO | {:15} | {}\n",
188                    dur.as_secs(),
189                    dur.subsec_nanos(),
190                    message.name,
191                    message.msg
192                )
193            }
194            Level::WARN => {
195                format!(
196                    "{:9}.{:0.09} |  WARN | {:15} | {}\n",
197                    dur.as_secs(),
198                    dur.subsec_nanos(),
199                    message.name,
200                    message.msg
201                )
202            }
203            Level::ERROR => {
204                format!(
205                    "{:9}.{:0.09} | ERROR | {:15} | {}\n",
206                    dur.as_secs(),
207                    dur.subsec_nanos(),
208                    message.name,
209                    message.msg
210                )
211            }
212            Level::FATAL => {
213                format!(
214                    "{:9}.{:0.09} | FATAL | {:15} | {}\n",
215                    dur.as_secs(),
216                    dur.subsec_nanos(),
217                    message.name,
218                    message.msg
219                )
220            }
221            Level::NONE => "".to_string(),
222        };
223
224        let mut out = self.out.write().unwrap();
225        out.write(data.as_bytes()).unwrap();
226        out.flush().unwrap();
227    }
228}
229
230///
231/// A logger node.
232///
233/// **note:** Normaly you should never have to create an instance by yourself.
234///
235#[derive(Clone)]
236pub struct _Logger {
237    _name: String,
238    _full_name: String,
239    /// The level of the logger.
240    pub level: Level,
241    _parent: Option<Arc<_Logger>>,
242    _handlers: Arc<RwLock<Vec<Arc<Box<Handler>>>>>,
243    _children: Arc<RwLock<HashMap<String, Arc<_Logger>>>>,
244}
245
246
247impl _Logger {
248    ///
249    ///  Add a new handler to the logger node.
250    ///
251    pub fn add_handler(&self, handler: Arc<Box<Handler>>) {
252        let mut hs = self._handlers.write().unwrap();
253        hs.push(handler);
254    }
255
256    //
257    // Removes all handlers from this logging node.
258    //
259    pub fn clear_handlers(&self) {
260        let mut hs = self._handlers.write().unwrap();
261        hs.clear();
262    }
263
264    /// Returns the name part of this logger.
265    pub fn name(&self) -> String {
266        self._name.clone()
267    }
268
269    /// Returns the full name of the logger.
270    pub fn full_name(&self) -> String {
271        self._full_name.clone()
272    }
273
274    ///
275    /// Logs a message.
276    ///
277    pub fn log(&self, level: Level, msg: &str) {
278        if self.level <= level {
279            let message = Message {
280                level: level,
281                name: self._full_name.clone(),
282                created: SystemTime::now(),
283                msg: String::from(msg),
284            };
285
286            self.log_msg(&message);
287        }
288    }
289
290    fn log_msg(&self, message: &Message) {
291        let hs = self._handlers.read().unwrap();
292        for h in hs.iter() {
293            h.emit(&message);
294        }
295
296        if let Some(ref parent) = self._parent {
297            parent.log_msg(message);
298        }
299    }
300
301    ///
302    /// Logs a debug message.
303    ///
304    pub fn debug(&self, fmt: &str) {
305        self.log(Level::DEBUG, fmt);
306    }
307
308    ///
309    /// Logs a info message.
310    ///
311    pub fn info(&self, fmt: &str) {
312        self.log(Level::INFO, fmt);
313    }
314
315    ///
316    /// Logs a warn message.
317    ///
318    pub fn warn(&self, fmt: &str) {
319        self.log(Level::WARN, fmt);
320    }
321
322    ///
323    /// Logs a error message.
324    ///
325    pub fn error(&self, fmt: &str) {
326        self.log(Level::ERROR, fmt);
327    }
328
329    ///
330    /// Logs a fatal message.
331    ///
332    pub fn fatal(&self, fmt: &str) {
333        self.log(Level::FATAL, fmt);
334    }
335}
336
337/// A logger instance.
338pub type Logger = Arc<_Logger>;
339
340static mut ROOT: *const Logger = 0 as *const Logger;
341
342fn init() {
343    // make rust unsafe again!
344    unsafe {
345        if ROOT == (0 as *const Logger) {
346            let root = Box::new(Arc::new(_Logger {
347                _name: String::new(),
348                _full_name: String::new(),
349                level: Level::DEBUG,
350                _parent: None,
351                _handlers: Arc::new(RwLock::new(Vec::new())),
352                _children: Arc::new(RwLock::new(HashMap::new())),
353            }));
354
355            // root.add_handler(ConsoleHandler::new());
356            ROOT = std::mem::transmute(root);
357        }
358    }
359}
360
361///
362/// Gets the root logger.
363///
364pub fn root() -> Logger {
365    init();
366    unsafe { (*ROOT).clone() }
367}
368
369///
370/// Convenient debug log to the root logger.
371///
372pub fn debug(fmt: &str) {
373    init();
374
375    let result = unsafe { (*ROOT).clone() };
376
377    result.log(Level::DEBUG, fmt);
378}
379
380///
381/// Convenient info log to the root logger.
382///
383pub fn info(fmt: &str) {
384    init();
385
386    let result = unsafe { (*ROOT).clone() };
387
388    result.log(Level::INFO, fmt);
389}
390
391///
392/// Convenient warn log to the root logger.
393///
394pub fn warn(fmt: &str) {
395    init();
396
397    let result = unsafe { (*ROOT).clone() };
398
399    result.log(Level::WARN, fmt);
400}
401
402///
403/// Convenient error log to the root logger.
404///
405pub fn error(fmt: &str) {
406    init();
407
408    let result = unsafe { (*ROOT).clone() };
409
410    result.log(Level::ERROR, fmt);
411}
412
413///
414/// Convenient fatal log to the root logger.
415///
416pub fn fatal(fmt: &str) {
417    init();
418
419    let result = unsafe { (*ROOT).clone() };
420
421    result.log(Level::FATAL, fmt);
422}
423
424///
425/// Gets a Logger instance by it's name.
426///
427/// ```
428/// let log = logging::get("my.app".to_owned());
429/// ```
430///
431pub fn get(name: &str) -> Logger {
432    init();
433
434    let path: Vec<&str> = name.split(".").collect();
435    let mut result = unsafe { (*ROOT).clone() };
436
437    for (idx, step) in path.iter().enumerate() {
438        result = {
439            let mut map = result._children.write().unwrap();
440
441            map.entry(step.to_string())
442                .or_insert_with(|| {
443                    let full = path[1..idx + 1].iter().fold(
444                        String::from(path[0]),
445                        |a, b| format!("{}.{}", a, b),
446                    );
447
448                    Arc::new(_Logger {
449                        _name: step.to_string(),
450                        _full_name: full,
451                        level: Level::DEBUG,
452                        _parent: Some(result.clone()),
453                        _handlers: Arc::new(RwLock::new(Vec::new())),
454                        _children: Arc::new(RwLock::new(HashMap::new())),
455                    })
456                })
457                .clone()
458        };
459    }
460
461    result
462}