1use crate::buf_file_impl::LogBufFile;
2use crate::console_impl::LogConsole;
3use crate::file_impl::LogRawFile;
4use crate::log_impl::setup_log;
5use crate::{
6 formatter::{FormatRecord, TimeFormatter},
7 log_impl::LogSink,
8 time::Timer,
9};
10use log::{Level, LevelFilter, Record};
11use std::hash::{DefaultHasher, Hash, Hasher};
12use std::path::Path;
13
14#[derive(Default)]
17pub struct Builder {
18 pub dynamic: bool,
25
26 pub rotation_signals: Vec<i32>,
29
30 pub panic: bool,
32
33 pub continue_when_panic: bool,
35
36 pub(crate) sinks: Vec<Box<dyn SinkConfigTrait>>,
38}
39
40impl Builder {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn test(mut self) -> Self {
48 self.dynamic = true;
49 self.rotation_signals.clear();
50 self
51 }
52
53 pub fn signal(mut self, signal: i32) -> Self {
55 self.rotation_signals.push(signal);
56 self
57 }
58
59 pub fn raw_file(mut self, config: LogRawFile) -> Self {
61 self.sinks.push(Box::new(config));
62 self
63 }
64
65 pub fn buf_file(mut self, config: LogBufFile) -> Self {
67 self.sinks.push(Box::new(config));
68 self
69 }
70
71 pub fn console(mut self, config: LogConsole) -> Self {
73 self.sinks.push(Box::new(config));
74 self
75 }
76
77 #[cfg(feature = "syslog")]
78 pub fn syslog(mut self, config: crate::Syslog) -> Self {
80 self.sinks.push(Box::new(config));
81 self
82 }
83
84 pub fn get_max_level(&self) -> LevelFilter {
86 let mut max_level = Level::Error;
87 for sink in &self.sinks {
88 let level = sink.get_level();
89 if level > max_level {
90 max_level = level;
91 }
92 }
93 return max_level.to_level_filter();
94 }
95
96 pub(crate) fn cal_checksum(&self) -> u64 {
98 let mut hasher = Box::new(DefaultHasher::new()) as Box<dyn Hasher>;
99 self.dynamic.hash(&mut hasher);
100 self.rotation_signals.hash(&mut hasher);
101 self.panic.hash(&mut hasher);
102 self.continue_when_panic.hash(&mut hasher);
103 for sink in &self.sinks {
104 sink.write_hash(&mut hasher);
105 }
106 hasher.finish()
107 }
108
109 pub fn build(self) -> Result<(), ()> {
112 setup_log(self)
113 }
114}
115
116pub(crate) trait SinkConfigTrait {
117 fn get_level(&self) -> Level;
119 #[allow(dead_code)]
121 fn get_file_path(&self) -> Option<Box<Path>>;
122 fn write_hash(&self, hasher: &mut Box<dyn Hasher>);
124 fn build(&self) -> LogSink;
126}
127
128pub type FormatFunc = fn(FormatRecord) -> String;
129
130#[derive(Clone, Hash)]
132pub struct LogFormat {
133 time_fmt: &'static str,
134 format_fn: FormatFunc,
135}
136
137impl LogFormat {
138 pub const fn new(time_fmt: &'static str, format_fn: FormatFunc) -> Self {
161 Self { time_fmt, format_fn }
162 }
163
164 #[inline(always)]
165 pub(crate) fn process(&self, now: &Timer, record: &Record) -> String {
166 let time = TimeFormatter { now, fmt_str: self.time_fmt };
167 let r = FormatRecord { record, time };
168 return (self.format_fn)(r);
169 }
170}