1use crate::log_impl::setup_log;
2use crate::{
3 console_impl::LoggerSinkConsole,
4 file_impl::LoggerSinkFile,
5 formatter::{FormatRecord, TimeFormatter},
6 log_impl::LoggerSink,
7 time::Timer,
8};
9use log::{Level, LevelFilter, Record};
10use std::hash::{DefaultHasher, Hash, Hasher};
11use std::path::Path;
12
13#[derive(Default)]
16pub struct Builder {
17 pub dynamic: bool,
24
25 pub rotation_signals: Vec<i32>,
28
29 pub panic: bool,
31
32 pub continue_when_panic: bool,
34
35 pub sinks: Vec<Box<dyn SinkConfigTrait>>,
37}
38
39impl Builder {
40 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn test(mut self) -> Self {
47 self.dynamic = true;
48 self.rotation_signals.clear();
49 self
50 }
51
52 pub fn signal(mut self, signal: i32) -> Self {
54 self.rotation_signals.push(signal);
55 self
56 }
57
58 pub fn raw_file(mut self, config: LogRawFile) -> Self {
60 self.sinks.push(Box::new(config));
61 self
62 }
63
64 pub fn console(mut self, config: LogConsole) -> Self {
66 self.sinks.push(Box::new(config));
67 self
68 }
69
70 pub fn get_max_level(&self) -> LevelFilter {
72 let mut max_level = Level::Error;
73 for sink in &self.sinks {
74 let level = sink.get_level();
75 if level > max_level {
76 max_level = level;
77 }
78 }
79 return max_level.to_level_filter();
80 }
81
82 pub(crate) fn cal_checksum(&self) -> u64 {
84 let mut hasher = Box::new(DefaultHasher::new()) as Box<dyn Hasher>;
85 self.dynamic.hash(&mut hasher);
86 self.rotation_signals.hash(&mut hasher);
87 self.panic.hash(&mut hasher);
88 self.continue_when_panic.hash(&mut hasher);
89 for sink in &self.sinks {
90 sink.write_hash(&mut hasher);
91 }
92 hasher.finish()
93 }
94
95 pub fn build(self) -> Result<(), ()> {
98 setup_log(self)
99 }
100}
101
102pub trait SinkConfigTrait {
103 fn get_level(&self) -> Level;
105 fn get_file_path(&self) -> Option<Box<Path>>;
107 fn write_hash(&self, hasher: &mut Box<dyn Hasher>);
109 fn build(&self) -> LoggerSink;
111}
112
113pub type FormatFunc = fn(FormatRecord) -> String;
114
115#[derive(Clone, Hash)]
117pub struct LogFormat {
118 time_fmt: String,
119 format_fn: FormatFunc,
120}
121
122impl LogFormat {
123 pub fn new(time_fmt: &str, format_fn: FormatFunc) -> Self {
146 Self { time_fmt: time_fmt.to_string(), format_fn }
147 }
148
149 #[inline(always)]
150 pub(crate) fn process(&self, now: &Timer, record: &Record) -> String {
151 let time = TimeFormatter { now, fmt_str: &self.time_fmt };
152 let r = FormatRecord { record, time };
153 return (self.format_fn)(r);
154 }
155}
156
157#[derive(Hash)]
160pub struct LogRawFile {
161 pub dir: String,
163
164 pub level: Level,
166
167 pub name: String,
169
170 pub format: LogFormat,
171
172 pub file_path: Box<Path>,
174}
175
176impl LogRawFile {
177 pub fn new(dir: &str, name: &str, level: Level, format: LogFormat) -> Self {
178 let file_path = Path::new(dir).join(Path::new(name)).into_boxed_path();
179 Self { dir: dir.to_string(), name: name.to_string(), level, format, file_path }
180 }
181}
182
183impl SinkConfigTrait for LogRawFile {
184 fn get_level(&self) -> Level {
185 self.level
186 }
187
188 fn get_file_path(&self) -> Option<Box<Path>> {
189 Some(self.file_path.clone())
190 }
191
192 fn write_hash(&self, hasher: &mut Box<dyn Hasher>) {
193 self.hash(hasher);
194 hasher.write(b"LogRawFile");
195 }
196
197 fn build(&self) -> LoggerSink {
198 LoggerSink::File(LoggerSinkFile::new(self))
199 }
200}
201
202#[derive(Copy, Clone, Debug, Hash)]
203#[repr(u8)]
204pub enum ConsoleTarget {
205 Stdout = 1,
206 Stderr = 2,
207}
208
209#[derive(Hash)]
210pub struct LogConsole {
211 pub target: ConsoleTarget,
212
213 pub level: Level,
215
216 pub format: LogFormat,
217}
218
219impl LogConsole {
220 pub fn new(target: ConsoleTarget, level: Level, format: LogFormat) -> Self {
221 Self { target, level, format }
222 }
223}
224
225impl SinkConfigTrait for LogConsole {
226 fn get_level(&self) -> Level {
227 self.level
228 }
229
230 fn get_file_path(&self) -> Option<Box<Path>> {
231 None
232 }
233
234 fn write_hash(&self, hasher: &mut Box<dyn Hasher>) {
235 self.hash(hasher);
236 hasher.write(b"LogConsole");
237 }
238
239 fn build(&self) -> LoggerSink {
240 LoggerSink::Console(LoggerSinkConsole::new(self))
241 }
242}