r3bl_simple_logger/loggers/
testlog.rs1use std::thread;
21
22use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};
23
24use super::logging::should_skip;
25use crate::{config::TimeFormat, Config, LevelPadding, SharedLogger};
26
27pub struct TestLogger {
29 level: LevelFilter,
30 config: Config,
31}
32
33impl TestLogger {
34 pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
50 set_max_level(log_level);
51 set_boxed_logger(TestLogger::new(log_level, config))
52 }
53
54 #[must_use]
72 pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
73 Box::new(TestLogger {
74 level: log_level,
75 config,
76 })
77 }
78}
79
80impl Log for TestLogger {
81 fn enabled(&self, metadata: &Metadata<'_>) -> bool {
82 metadata.level() <= self.level
83 }
84
85 fn log(&self, record: &Record<'_>) {
86 if self.enabled(record.metadata()) {
87 log(&self.config, record);
88 }
89 }
90
91 fn flush(&self) {}
92}
93
94impl SharedLogger for TestLogger {
95 fn level(&self) -> LevelFilter {
96 self.level
97 }
98
99 fn config(&self) -> Option<&Config> {
100 Some(&self.config)
101 }
102
103 fn as_log(self: Box<Self>) -> Box<dyn Log> {
104 Box::new(*self)
105 }
106}
107
108#[inline(always)]
109pub fn log(config: &Config, record: &Record<'_>) {
110 if should_skip(config, record) {
111 return;
112 }
113
114 if config.time <= record.level() && config.time != LevelFilter::Off {
115 write_time(config);
116 }
117
118 if config.level <= record.level() && config.level != LevelFilter::Off {
119 write_level(record, config);
120 }
121
122 if config.thread < record.level() && config.thread != LevelFilter::Off {
123 write_thread_id();
124 }
125
126 if config.target <= record.level() && config.target != LevelFilter::Off {
127 write_target(record);
128 }
129
130 if config.location <= record.level() && config.location != LevelFilter::Off {
131 write_location(record);
132 }
133
134 if config.module <= record.level() && config.module != LevelFilter::Off {
135 write_module(record);
136 }
137
138 write_args(record);
139}
140
141#[inline(always)]
142pub fn write_time(config: &Config) {
143 use time::format_description::well_known::*;
144
145 let time = time::OffsetDateTime::now_utc().to_offset(config.time_offset);
146 let res = match config.time_format {
147 TimeFormat::Rfc2822 => time.format(&Rfc2822),
148 TimeFormat::Rfc3339 => time.format(&Rfc3339),
149 TimeFormat::Custom(format) => time.format(&format),
150 };
151 match res {
152 Ok(time) => print!("{} ", time),
153 Err(err) => panic!("Invalid time format: {}", err),
154 };
155}
156
157#[inline(always)]
158pub fn write_level(record: &Record<'_>, config: &Config) {
159 match config.level_padding {
160 LevelPadding::Left => print!("[{: >5}] ", record.level()),
161 LevelPadding::Right => print!("[{: <5}] ", record.level()),
162 LevelPadding::Off => print!("[{}] ", record.level()),
163 };
164}
165
166#[inline(always)]
167pub fn write_thread_id() {
168 let id = format!("{:?}", thread::current().id());
169 let id = id.replace("ThreadId(", "");
170 let id = id.replace(')', "");
171 print!("({}) ", id);
172}
173
174#[inline(always)]
175pub fn write_target(record: &Record<'_>) {
176 print!("{}: ", record.target());
177}
178
179#[inline(always)]
180pub fn write_location(record: &Record<'_>) {
181 let file = record.file().unwrap_or("<unknown>");
182 if let Some(line) = record.line() {
183 print!("[{}:{}] ", file, line);
184 } else {
185 print!("[{}:<unknown>] ", file);
186 }
187}
188
189#[inline(always)]
190pub fn write_module(record: &Record<'_>) {
191 let module = record.module_path().unwrap_or("<unknown>");
192 print!("[{}] ", module);
193}
194
195#[inline(always)]
196pub fn write_args(record: &Record<'_>) {
197 println!("{}", record.args());
198}