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 time_fmt: String,
13 format_fn: FormatFunc,
14}
15
16impl LogFormat {
17 pub fn new(time_fmt: &str, format_fn: FormatFunc) -> Self {
40 Self { time_fmt: time_fmt.to_string(), format_fn }
41 }
42
43 #[inline(always)]
44 pub fn process(&self, now: &Timer, record: &Record) -> String {
45 let time = TimeFormatter { now, fmt_str: &self.time_fmt };
46 let r = FormatRecord { record, time };
47 return (self.format_fn)(r);
48 }
49}
50
51pub struct TimeFormatter<'a> {
52 pub now: &'a Timer,
53 pub fmt_str: &'a String,
54}
55
56impl<'a> TimeFormatter<'a> {
57 #[inline(always)]
58 fn time_str(&self) -> String {
59 self.now.format(&self.fmt_str).to_string()
60 }
61}
62
63pub struct FormatRecord<'a> {
64 pub record: &'a Record<'a>,
65 pub time: TimeFormatter<'a>,
66}
67
68impl<'a> FormatRecord<'a> {
69 #[inline(always)]
70 pub fn file(&self) -> &str {
71 basename(self.record.file().unwrap_or("<none>"))
72 }
73
74 #[inline(always)]
75 pub fn line(&self) -> u32 {
76 self.record.line().unwrap_or(0)
77 }
78
79 #[inline(always)]
80 pub fn time(&self) -> String {
81 self.time.time_str()
82 }
83
84 #[inline(always)]
85 pub fn key(&self, key: &str) -> String {
86 let source = self.record.key_values();
87 if let Some(v) = source.get(Key::from_str(key)) {
88 return format!(" ({})", v).to_string();
89 } else {
90 return "".to_string();
91 }
92 }
93
94 #[inline(always)]
95 pub fn level(&self) -> Level {
96 self.record.level()
97 }
98
99 #[inline(always)]
100 pub fn msg(&self) -> &'a fmt::Arguments<'a> {
101 self.record.args()
102 }
103}
104
105fn basename(path: &str) -> &str {
106 let res = path.rfind('/');
107 match res {
108 Some(idx) => path.get(idx + 1..).unwrap_or(path),
109 None => path,
110 }
111}