1use std::fmt;
2use std::fs::OpenOptions;
3use std::io::prelude::*;
4use str_util::empty_string;
5
6const TAGS: [&str; 4] = ["[info]", "[debug]", "[warning]", "[error]"];
8const CLEAR_THRESHOLD: usize = 8192;
9
10#[derive(Debug, Clone)]
12struct Entry {
13 level: usize,
14 message: String,
15}
16
17impl Entry {
18 #[inline]
20 fn new(level: usize, message: String) -> Entry {
21 Entry {
22 level: level,
23 message: message,
24 }
25 }
26
27 #[inline]
29 fn render(&self) -> String {
30 format!("{} {}", TAGS[self.level], self.message)
31 }
32}
33
34#[derive(Debug)]
36pub struct Log {
37 log: Vec<Entry>,
38 write_status: u32,
39 log_file: String,
40}
41
42impl Log {
43 #[inline]
45 pub fn new() -> Log {
46 Log {
47 log: Vec::new(),
48 write_status: 0,
49 log_file: empty_string(),
50 }
51 }
52
53 #[inline]
55 fn add_entry(&mut self, level: usize, message: String) {
56 if self.log.len() > CLEAR_THRESHOLD {
57 self.clear();
58 }
59
60 let entry = Entry::new(level, message);
61 let log_len: usize = self.log.len();
62 self.log.push(entry.clone());
63
64 match self.write_status {
65 1 => {
66 println!("{}", entry.render());
67 }
68 2 => {
69 self.save_entry(log_len);
70 }
71 3 => {
72 println!("{}", entry.render());
73 self.save_entry(log_len);
74 }
75 _ => {}
76 }
77 }
78
79 fn save_entry(&self, index: usize) {
80 let entry: String = self.log[index].render();
81
82 let mut handle = OpenOptions::new()
83 .write(true)
84 .append(true)
85 .create(true)
86 .open(&self.log_file)
87 .unwrap();
88
89 let _ = writeln!(&mut handle, "{}", entry);
90 }
91
92 #[inline]
94 pub fn set_log_file(&mut self, log_path: String) {
95 self.log_file = log_path;
96 }
97
98 #[inline]
99 pub fn info(&mut self, message: String) {
100 self.add_entry(0, message);
101 }
102
103 #[inline]
104 pub fn debug(&mut self, message: String) {
105 self.add_entry(1, message);
106 }
107
108 #[inline]
109 pub fn warning(&mut self, message: String) {
110 self.add_entry(2, message);
111 }
112
113 #[inline]
114 pub fn error(&mut self, message: String) {
115 self.add_entry(3, message);
116 }
117
118 #[inline]
129 pub fn set_write(&mut self, mode: u32) {
130 self.write_status = mode;
131 }
132
133 #[inline]
135 pub fn clear(&mut self) {
136 self.log.clear();
137 }
138
139 pub fn render(&self) -> Vec<String> {
141 let mut textlog: Vec<String> = Vec::new();
142
143 for entry in &self.log {
144 textlog.push(format!("{} {}", TAGS[entry.level], entry.message));
145 }
146
147 textlog
148 }
149}
150
151impl fmt::Display for Entry {
152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 writeln!(f, "{}", &self.render())?;
154 Ok(())
155 }
156}
157
158impl fmt::Display for Log {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 for line in &self.render() {
161 writeln!(f, "{}", line)?;
162 }
163 Ok(())
164 }
165}