1use std::cmp::Ordering;
2use std::io::{self, Write};
3use std::sync::Mutex;
4
5#[derive(PartialEq, Eq)]
6pub enum LogLevel {
7 Debug,
8 Info,
9 Warn,
10 Error,
11}
12
13
14
15impl PartialOrd for LogLevel {
16 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
17 match (self, other) {
18 (&LogLevel::Error, &LogLevel::Error) => Some(Ordering::Equal),
19 (&LogLevel::Error, _) => Some(Ordering::Greater),
20 (_, &LogLevel::Error) => Some(Ordering::Less),
21 (&LogLevel::Warn, &LogLevel::Warn) => Some(Ordering::Equal),
22 (&LogLevel::Warn, _) => Some(Ordering::Greater),
23 (_, &LogLevel::Warn) => Some(Ordering::Less),
24 (&LogLevel::Info, &LogLevel::Info) => Some(Ordering::Equal),
25 (&LogLevel::Info, _) => Some(Ordering::Greater),
26 (_, &LogLevel::Info) => Some(Ordering::Less),
27 (&LogLevel::Debug, &LogLevel::Debug) => Some(Ordering::Equal),
28 }
29 }
30}
31
32impl Ord for LogLevel {
33 fn cmp(&self, other: &Self) -> Ordering {
34 match (self, other) {
35 (&LogLevel::Error, &LogLevel::Error)
36 | (&LogLevel::Warn, &LogLevel::Warn)
37 | (&LogLevel::Info, &LogLevel::Info)
38 | (&LogLevel::Debug, &LogLevel::Debug) => Ordering::Equal,
39 (&LogLevel::Error, _) => Ordering::Greater,
40 (_, &LogLevel::Error) => Ordering::Less,
41 (&LogLevel::Warn, &LogLevel::Info)
42 | (&LogLevel::Warn, &LogLevel::Debug)
43 | (&LogLevel::Info, &LogLevel::Debug) => Ordering::Greater,
44 (_, _) => Ordering::Less,
45 }
46 }
47}
48
49
50pub struct Logger {
51 level: LogLevel,
52 writer: Mutex<Box<dyn Write + Send>>,
53}
54
55impl Logger {
56 pub fn new(level: LogLevel) -> Self {
57 Logger {
58 level,
59 writer: Mutex::new(Box::new(io::stdout())),
60 }
61 }
62
63 pub fn set_writer(&self, writer: Box<dyn Write + Send>) {
64 *self.writer.lock().unwrap() = writer;
65 }
66
67 fn log(&self, level: LogLevel, message: &str) {
68 if level >= self.level {
69 let mut writer = self.writer.lock().unwrap();
70 writeln!(writer.as_mut(), "{}: {}", level_str(level), message).unwrap();
71 }
72 }
73
74 pub fn debug(&self, message: &str) {
75 self.log(LogLevel::Debug, message);
76 }
77
78 pub fn info(&self, message: &str) {
79 self.log(LogLevel::Info, message);
80 }
81
82 pub fn warn(&self, message: &str) {
83 self.log(LogLevel::Warn, message);
84 }
85
86 pub fn error(&self, message: &str) {
87 self.log(LogLevel::Error, message);
88 }
89}
90
91fn level_str(level: LogLevel) -> &'static str {
92 match level {
93 LogLevel::Debug => "DEBUG",
94 LogLevel::Info => "INFO",
95 LogLevel::Warn => "WARN",
96 LogLevel::Error => "ERROR",
97 }
98}
99
100