captains_log/
formatter.rs1use std::*;
2
3use log::{kv::Key, *};
4
5use crate::time::Timer;
6
7pub type FormatFunc = fn(FormatRecord) -> String;
8
9#[derive(Clone)]
10pub struct LogFormat
12{
13 time_fmt: String,
14 format_fn: FormatFunc,
15}
16
17impl LogFormat {
18
19 pub fn new(time_fmt: &str, format_fn: FormatFunc) -> Self {
42 Self{
43 time_fmt: time_fmt.to_string(),
44 format_fn,
45 }
46 }
47
48 #[inline(always)]
49 pub fn process(&self, now: &Timer, record: &Record) -> String {
50 let time = TimeFormatter{
51 now, fmt_str: &self.time_fmt,
52 };
53 let r = FormatRecord{
54 record, time,
55 };
56 return (self.format_fn)(r);
57 }
58}
59
60pub struct TimeFormatter<'a> {
61 pub now: &'a Timer,
62 pub fmt_str: &'a String,
63}
64
65impl<'a> TimeFormatter<'a> {
66
67 #[inline(always)]
68 fn time_str(&self) -> String {
69 self.now.format(&self.fmt_str).to_string()
70 }
71}
72
73pub struct FormatRecord<'a> {
74 pub record: &'a Record<'a>,
75 pub time: TimeFormatter<'a>
76}
77
78impl<'a> FormatRecord<'a> {
79
80 #[inline(always)]
81 pub fn file(&self) -> &str {
82 basename(self.record.file().unwrap_or("<none>"))
83 }
84
85 #[inline(always)]
86 pub fn line(&self) -> u32 {
87 self.record.line().unwrap_or(0)
88 }
89
90 #[inline(always)]
91 pub fn time(&self) -> String {
92 self.time.time_str()
93 }
94
95 #[inline(always)]
96 pub fn key(&self, key: &str) -> String {
97 let source = self.record.key_values();
98 if let Some(v) = source.get(Key::from_str(key)) {
99 return format!(" ({})", v).to_string()
100 } else {
101 return "".to_string()
102 }
103 }
104
105 #[inline(always)]
106 pub fn level(&self) -> Level {
107 self.record.level()
108 }
109
110 #[inline(always)]
111 pub fn msg(&self) -> &'a fmt::Arguments<'a> {
112 self.record.args()
113 }
114}
115
116fn basename(path: &str) -> &str {
117 let res = path.rfind('/');
118 match res {
119 Some(idx) => path.get(idx + 1..).unwrap_or(path),
120 None => path,
121 }
122}