captains_log/
formatter.rs

1use log::{kv::Key, *};
2use std::{fmt, thread};
3
4use crate::time::Timer;
5
6pub struct TimeFormatter<'a> {
7    pub now: &'a Timer,
8    pub fmt_str: &'a str,
9}
10
11impl<'a> TimeFormatter<'a> {
12    #[inline(always)]
13    fn time_str(&self) -> String {
14        self.now.format(self.fmt_str).to_string()
15    }
16}
17
18pub struct FormatRecord<'a> {
19    pub record: &'a Record<'a>,
20    pub time: TimeFormatter<'a>,
21}
22
23impl<'a> FormatRecord<'a> {
24    #[inline(always)]
25    pub fn file(&self) -> &str {
26        basename(self.record.file().unwrap_or("<none>"))
27    }
28
29    #[inline(always)]
30    pub fn line(&self) -> u32 {
31        self.record.line().unwrap_or(0)
32    }
33
34    #[inline(always)]
35    pub fn timestamp_nano(&self) -> i64 {
36        self.time.now.timestamp_nanos_opt().unwrap_or(0)
37    }
38
39    #[inline(always)]
40    pub fn time(&self) -> String {
41        self.time.time_str()
42    }
43
44    #[inline(always)]
45    pub fn key(&self, key: &str) -> String {
46        let source = self.record.key_values();
47        if let Some(v) = source.get(Key::from_str(key)) {
48            return format!(" ({})", v).to_string();
49        } else {
50            return "".to_string();
51        }
52    }
53
54    #[inline(always)]
55    pub fn level(&self) -> Level {
56        self.record.level()
57    }
58
59    #[inline(always)]
60    pub fn msg(&self) -> &'a fmt::Arguments<'a> {
61        self.record.args()
62    }
63
64    #[inline(always)]
65    pub fn thread_id(&self) -> thread::ThreadId {
66        thread::current().id()
67    }
68}
69
70fn basename(path: &str) -> &str {
71    let res = path.rfind('/');
72    match res {
73        Some(idx) => path.get(idx + 1..).unwrap_or(path),
74        None => path,
75    }
76}