nonblock_logger/
formater.rs

1use log::{Level, Record};
2
3use std::convert::AsRef;
4use std::{fmt, mem, thread};
5
6pub trait Formater: Send + Sync + 'static {
7    fn boxed(self) -> Box<dyn Formater>;
8    fn format(&self, record: &Record) -> String;
9}
10
11impl Formater for BaseFormater {
12    fn boxed(self) -> Box<dyn Formater> {
13        Box::new(self) as _
14    }
15
16    fn format(&self, record: &Record) -> String {
17        self.formater_get()(self, record)
18    }
19}
20
21pub fn format(base: &BaseFormater, record: &Record) -> String {
22    let datetime = if base.local_get() {
23        chrono::Local::now().format(base.datetime_get())
24    } else {
25        chrono::Utc::now().format(base.datetime_get())
26    };
27
28    #[cfg(any(feature = "color"))]
29    let level = FixedLevel::with_color(record.level(), base.color_get())
30        .length(base.level_get())
31        .into_colored()
32        .into_coloredfg();
33    #[cfg(not(feature = "color"))]
34    let level = FixedLevel::new(record.level()).length(base.level_get());
35
36    current_thread_name(|ctn| {
37        format!(
38            "{} {} [{}] ({}:{}) [{}] -- {}\n",
39            datetime,
40            level,
41            ctn,
42            record.file().unwrap_or("*"),
43            record.line().unwrap_or(0),
44            record.target(),
45            record.args()
46        )
47    })
48}
49
50impl fmt::Debug for BaseFormater {
51    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
52        #[cfg(any(feature = "color"))]
53        return fmt
54            .debug_struct("BaseFormater")
55            .field("local", &self.local)
56            .field("level", &self.level)
57            .field("datetime", &self.datetime)
58            .field("color", &self.color)
59            .finish();
60
61        #[cfg(not(feature = "color"))]
62        fmt.debug_struct("BaseFormater")
63            .field("local", &self.local)
64            .field("level", &self.level)
65            .field("datetime", &self.datetime)
66            .finish()
67    }
68}
69
70// #[derive(Debug)]
71pub struct BaseFormater {
72    local: bool,
73    level: usize,
74    datetime: String,
75    formater: Box<dyn Fn(&Self, &Record) -> String + Send + Sync + 'static>,
76    #[cfg(any(feature = "color"))]
77    color: ColoredLogConfig,
78}
79
80impl Default for BaseFormater {
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl BaseFormater {
87    pub fn new() -> Self {
88        Self {
89            local: false,
90            level: 5,
91            formater: Box::new(format) as _,
92            datetime: "%Y-%m-%d %H:%M:%S.%3f".to_owned(),
93            #[cfg(any(feature = "color"))]
94            color: ColoredLogConfig::new(),
95        }
96    }
97
98    pub fn local(mut self, local: bool) -> Self {
99        self.local = local;
100        self
101    }
102
103    #[inline]
104    pub fn local_get(&self) -> bool {
105        self.local
106    }
107
108    pub fn level(mut self, chars: usize) -> Self {
109        self.level = chars;
110        self
111    }
112
113    #[inline]
114    pub fn level_get(&self) -> usize {
115        self.level
116    }
117
118    pub fn datetime<S: Into<String>>(mut self, datetime: S) -> Self {
119        self.datetime = datetime.into();
120        self
121    }
122
123    #[inline]
124    pub fn datetime_get(&self) -> &str {
125        &self.datetime
126    }
127
128    pub fn formater<F>(mut self, formater: F) -> Self
129    where
130        F: Fn(&Self, &Record) -> String + Send + Sync + 'static,
131    {
132        self.formater = Box::new(formater) as _;
133        self
134    }
135
136    #[inline]
137    pub fn formater_get(&self) -> &(dyn Fn(&Self, &Record) -> String + Send + Sync + 'static) {
138        &*self.formater
139    }
140
141    #[cfg(any(feature = "color"))]
142    pub fn color(mut self, color_: bool) -> Self {
143        self.color.color = color_;
144        self
145    }
146
147    #[inline]
148    #[cfg(any(feature = "color"))]
149    pub fn color_get(&self) -> &ColoredLogConfig {
150        &self.color
151    }
152
153    #[cfg(any(feature = "color"))]
154    pub fn colored(mut self, color: ColoredLogConfig) -> Self {
155        self.color = color;
156        self
157    }
158}
159
160pub fn current_thread_name<F, U>(f: F) -> U
161where
162    F: Fn(&str) -> U,
163{
164    struct ThreadId(u64);
165
166    thread_local!(static THREAD_NAME: String = {
167        let thread = thread::current();
168        format!("{}.{}", unsafe { mem::transmute::<_, ThreadId>(thread.id()).0 }, thread.name()
169        .map(|s| s.to_owned())
170        // unamed thread, main has 4 chars, aligned
171        .unwrap_or_else(||"****".to_owned()))
172    });
173
174    THREAD_NAME.with(|tname| f(&tname))
175}
176
177#[derive(Debug, Clone, Copy)]
178pub struct FixedLevel {
179    str: &'static str,
180    length: usize,
181    #[cfg(any(feature = "color"))]
182    color: Option<Color>,
183}
184
185impl FixedLevel {
186    #[inline]
187    pub fn new(level: Level) -> Self {
188        let str = match level {
189            Level::Trace => "TRACE",
190            Level::Debug => "DEBUG",
191            Level::Info => "INFO ",
192            Level::Warn => "WARN ",
193            Level::Error => "ERROR",
194        };
195
196        Self {
197            str,
198            length: 5,
199            #[cfg(any(feature = "color"))]
200            color: None,
201        }
202    }
203
204    #[inline]
205    pub fn length(mut self, length: usize) -> Self {
206        debug_assert!(length <= 5);
207        self.length = length;
208        self
209    }
210
211    #[inline]
212    #[cfg(any(feature = "color"))]
213    pub fn with_color(level: Level, color_: &ColoredLogConfig) -> Self {
214        let (str, color) = match level {
215            Level::Trace => ("TRACE", color_.trace),
216            Level::Debug => ("DEBUG", color_.debug),
217            Level::Info => ("INFO ", color_.info),
218            Level::Warn => ("WARN ", color_.warn),
219            Level::Error => ("ERROR", color_.error),
220        };
221
222        Self {
223            str,
224            length: 5,
225            color: if color_.color { Some(color) } else { None },
226        }
227    }
228
229    #[cfg(any(feature = "color"))]
230    pub fn into_colored(self) -> ColoredFixedLevel {
231        ColoredFixedLevel::new(self)
232    }
233}
234
235impl fmt::Display for FixedLevel {
236    #[inline]
237    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
238        fmt.write_str(self.as_ref())
239    }
240}
241
242impl AsRef<str> for FixedLevel {
243    #[inline]
244    fn as_ref(&self) -> &'static str {
245        unsafe { self.str.get_unchecked(0..self.length) }
246    }
247}
248
249#[cfg(any(feature = "color"))]
250use self::color::{Color, ColoredFixedLevel, ColoredLogConfig};
251#[cfg(any(feature = "color"))]
252pub mod color {
253    use super::FixedLevel;
254    use log::Level;
255    use std::{fmt, mem};
256    pub use yansi::Color;
257
258    pub struct ColoredFgWith<T> {
259        text: T,
260        color: Option<Color>,
261    }
262
263    impl<T> fmt::Display for ColoredFgWith<T>
264    where
265        T: fmt::Display,
266    {
267        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268            if let Some(color) = self.color.as_ref() {
269                write!(f, "{}", color.paint(&self.text))
270            } else {
271                write!(f, "{}", self.text)
272            }
273        }
274    }
275
276    #[derive(Debug, Clone)]
277    pub struct ColoredLogConfig {
278        pub error: Color,
279        pub warn: Color,
280        pub info: Color,
281        pub debug: Color,
282        pub trace: Color,
283        pub color: bool,
284    }
285
286    impl Default for ColoredLogConfig {
287        fn default() -> Self {
288            Self::new()
289        }
290    }
291
292    impl ColoredLogConfig {
293        #[inline]
294        pub fn new() -> Self {
295            Self {
296                error: Color::Red,
297                warn: Color::Yellow,
298                info: Color::Green,
299                debug: Color::Cyan,
300                trace: Color::Blue,
301                color: true,
302            }
303        }
304
305        pub fn error(mut self, error: Color) -> Self {
306            self.error = error;
307            self
308        }
309
310        pub fn warn(mut self, warn: Color) -> Self {
311            self.warn = warn;
312            self
313        }
314
315        pub fn info(mut self, info: Color) -> Self {
316            self.info = info;
317            self
318        }
319
320        pub fn debug(mut self, debug: Color) -> Self {
321            self.debug = debug;
322            self
323        }
324
325        pub fn trace(mut self, trace: Color) -> Self {
326            self.trace = trace;
327            self
328        }
329
330        pub fn color(mut self, color: bool) -> Self {
331            self.color = color;
332            self
333        }
334
335        pub fn coloredfg<T>(&self, level: Level, t: T) -> ColoredFgWith<T>
336        where
337            T: ColoredFg<T>,
338        {
339            t.coloredfg(level, self)
340        }
341    }
342
343    pub trait ColoredFg<T> {
344        fn coloredfg(self, level: Level, config: &ColoredLogConfig) -> ColoredFgWith<T>;
345    }
346
347    impl<T: fmt::Display> ColoredFg<T> for T {
348        fn coloredfg(self, level: Level, config: &ColoredLogConfig) -> ColoredFgWith<Self> {
349            let color = if config.color {
350                let colored = match level {
351                    Level::Error => config.error,
352                    Level::Warn => config.warn,
353                    Level::Info => config.info,
354                    Level::Debug => config.debug,
355                    Level::Trace => config.trace,
356                };
357                Some(colored)
358            } else {
359                None
360            };
361
362            ColoredFgWith { color, text: self }
363        }
364    }
365
366    // impl ColoredFg<ColoredFixedLevel> for ColoredFixedLevel {
367    //     #[inline]
368    //     fn coloredfg(self, _level: Level, _config: &ColoredLogConfig) -> ColoredFgWith<Self> {
369    //         self.into_coloredfg()
370    //     }
371    // }
372    // wait specialization for fixedLevel
373    #[derive(Debug, Clone, Copy)]
374    pub struct ColoredFixedLevel(FixedLevel);
375    impl ColoredFixedLevel {
376        #[inline]
377        pub fn new(fl: FixedLevel) -> Self {
378            ColoredFixedLevel(fl)
379        }
380
381        #[inline]
382        pub fn into_coloredfg(mut self) -> ColoredFgWith<Self> {
383            let color = mem::replace(&mut self.0.color, None);
384            ColoredFgWith { color, text: self }
385        }
386    }
387    impl fmt::Display for ColoredFixedLevel {
388        #[inline]
389        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
390            fmt.write_str(self.0.as_ref())
391        }
392    }
393}