1use crate::log_impl::setup_log;
2use crate::{
3 formatter::{FormatRecord, TimeFormatter},
4 log_impl::{LogSink, LogSinkTrait},
5 time::Timer,
6};
7use log::{Level, LevelFilter, Record};
8use std::hash::{DefaultHasher, Hash, Hasher};
9use std::path::Path;
10
11#[derive(Default)]
14pub struct Builder {
15 pub dynamic: bool,
22
23 pub rotation_signals: Vec<i32>,
26
27 pub panic: bool,
29
30 pub continue_when_panic: bool,
32
33 pub(crate) sinks: Vec<Box<dyn SinkConfigTrait>>,
35}
36
37impl Builder {
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn test(mut self) -> Self {
45 self.dynamic = true;
46 self.rotation_signals.clear();
47 self
48 }
49
50 pub fn signal(mut self, signal: i32) -> Self {
52 self.rotation_signals.push(signal);
53 self
54 }
55
56 pub fn add_sink<S: SinkConfigTrait>(mut self, config: S) -> Self {
58 self.sinks.push(Box::new(config));
59 self
60 }
61
62 pub fn get_max_level(&self) -> LevelFilter {
64 let mut max_level = Level::Error;
65 for sink in &self.sinks {
66 let level = sink.get_level();
67 if level > max_level {
68 max_level = level;
69 }
70 }
71 return max_level.to_level_filter();
72 }
73
74 pub(crate) fn cal_checksum(&self) -> u64 {
76 let mut hasher = Box::new(DefaultHasher::new()) as Box<dyn Hasher>;
77 self.dynamic.hash(&mut hasher);
78 self.rotation_signals.hash(&mut hasher);
79 self.panic.hash(&mut hasher);
80 self.continue_when_panic.hash(&mut hasher);
81 for sink in &self.sinks {
82 sink.write_hash(&mut hasher);
83 }
84 hasher.finish()
85 }
86
87 pub(crate) fn build_sinks(&self) -> Result<Vec<LogSink>, ()> {
88 let mut sinks = Vec::new();
89 for config in &self.sinks {
90 let logger_sink = config.build();
91 if let Err(e) = logger_sink.open() {
92 eprintln!("failed to open log sink: {:?}", e);
93 return Err(());
94 }
95 sinks.push(logger_sink);
96 }
97 Ok(sinks)
98 }
99
100 pub fn build(self) -> Result<(), ()> {
107 setup_log(self)
108 }
109}
110
111pub(crate) trait SinkConfigBuild {
112 fn build(&self) -> LogSink;
114}
115
116#[allow(private_bounds)]
117pub trait SinkConfigTrait: 'static + SinkConfigBuild {
118 fn get_level(&self) -> Level;
120 #[allow(dead_code)]
122 fn get_file_path(&self) -> Option<Box<Path>>;
123 fn write_hash(&self, hasher: &mut Box<dyn Hasher>);
125}
126
127pub type FormatFunc = fn(FormatRecord) -> String;
128
129#[derive(Clone, Hash)]
131pub struct LogFormat {
132 time_fmt: &'static str,
133 format_fn: FormatFunc,
134}
135
136impl LogFormat {
137 pub const fn new(time_fmt: &'static str, format_fn: FormatFunc) -> Self {
160 Self { time_fmt, format_fn }
161 }
162
163 #[inline(always)]
164 pub(crate) fn process(&self, now: &Timer, record: &Record) -> String {
165 let time = TimeFormatter { now, fmt_str: self.time_fmt };
166 let r = FormatRecord { record, time };
167 return (self.format_fn)(r);
168 }
169
170 #[inline(always)]
171 pub(crate) fn process_with_timestamp(&self, now: &Timer, record: &Record) -> (i64, String) {
172 let time = TimeFormatter { now, fmt_str: self.time_fmt };
173 let r = FormatRecord { record, time };
174 return (r.timestamp_nano(), (self.format_fn)(r));
175 }
176}