adaptive_pipeline_bootstrap/
logger.rs1#[cfg(test)]
40use std::fmt;
41
42pub trait BootstrapLogger: Send + Sync {
47 fn error(&self, message: &str);
51
52 fn warn(&self, message: &str);
56
57 fn info(&self, message: &str);
61
62 fn debug(&self, message: &str);
66}
67
68pub struct ConsoleLogger {
72 prefix: String,
73}
74
75impl ConsoleLogger {
76 pub fn new() -> Self {
78 Self::with_prefix("bootstrap")
79 }
80
81 pub fn with_prefix(prefix: impl Into<String>) -> Self {
83 Self { prefix: prefix.into() }
84 }
85}
86
87impl Default for ConsoleLogger {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl BootstrapLogger for ConsoleLogger {
94 fn error(&self, message: &str) {
95 tracing::error!(target: "bootstrap", "[{}] {}", self.prefix, message);
96 }
97
98 fn warn(&self, message: &str) {
99 tracing::warn!(target: "bootstrap", "[{}] {}", self.prefix, message);
100 }
101
102 fn info(&self, message: &str) {
103 tracing::info!(target: "bootstrap", "[{}] {}", self.prefix, message);
104 }
105
106 fn debug(&self, message: &str) {
107 tracing::debug!(target: "bootstrap", "[{}] {}", self.prefix, message);
108 }
109}
110
111pub struct NoOpLogger;
116
117impl NoOpLogger {
118 pub fn new() -> Self {
120 Self
121 }
122}
123
124impl Default for NoOpLogger {
125 fn default() -> Self {
126 Self::new()
127 }
128}
129
130impl BootstrapLogger for NoOpLogger {
131 fn error(&self, _message: &str) {}
132 fn warn(&self, _message: &str) {}
133 fn info(&self, _message: &str) {}
134 fn debug(&self, _message: &str) {}
135}
136
137#[cfg(test)]
141pub struct CapturingLogger {
142 messages: std::sync::Arc<std::sync::Mutex<Vec<LogMessage>>>,
143}
144
145#[cfg(test)]
146#[derive(Debug, Clone)]
147pub struct LogMessage {
148 pub level: LogLevel,
149 pub message: String,
150}
151
152#[cfg(test)]
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum LogLevel {
155 Error,
156 Warn,
157 Info,
158 Debug,
159}
160
161#[cfg(test)]
162impl Default for CapturingLogger {
163 fn default() -> Self {
164 Self::new()
165 }
166}
167
168#[cfg(test)]
169impl CapturingLogger {
170 pub fn new() -> Self {
171 Self {
172 messages: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
173 }
174 }
175
176 pub fn messages(&self) -> Vec<LogMessage> {
177 self.messages.lock().unwrap().clone()
178 }
179
180 pub fn clear(&self) {
181 self.messages.lock().unwrap().clear();
182 }
183
184 fn log(&self, level: LogLevel, message: &str) {
185 self.messages.lock().unwrap().push(LogMessage {
186 level,
187 message: message.to_string(),
188 });
189 }
190}
191
192#[cfg(test)]
193impl BootstrapLogger for CapturingLogger {
194 fn error(&self, message: &str) {
195 self.log(LogLevel::Error, message);
196 }
197
198 fn warn(&self, message: &str) {
199 self.log(LogLevel::Warn, message);
200 }
201
202 fn info(&self, message: &str) {
203 self.log(LogLevel::Info, message);
204 }
205
206 fn debug(&self, message: &str) {
207 self.log(LogLevel::Debug, message);
208 }
209}
210
211#[cfg(test)]
212impl fmt::Display for LogLevel {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 match self {
215 LogLevel::Error => write!(f, "ERROR"),
216 LogLevel::Warn => write!(f, "WARN"),
217 LogLevel::Info => write!(f, "INFO"),
218 LogLevel::Debug => write!(f, "DEBUG"),
219 }
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn test_console_logger_creation() {
229 let logger = ConsoleLogger::new();
230 logger.info("test message");
232 }
233
234 #[test]
235 fn test_console_logger_with_prefix() {
236 let logger = ConsoleLogger::with_prefix("custom");
237 logger.debug("test message");
239 }
240
241 #[test]
242 fn test_noop_logger() {
243 let logger = NoOpLogger::new();
244 logger.error("error");
246 logger.warn("warning");
247 logger.info("info");
248 logger.debug("debug");
249 }
250
251 #[test]
252 fn test_capturing_logger() {
253 let logger = CapturingLogger::new();
254
255 logger.error("error message");
256 logger.warn("warning message");
257 logger.info("info message");
258 logger.debug("debug message");
259
260 let messages = logger.messages();
261 assert_eq!(messages.len(), 4);
262
263 assert_eq!(messages[0].level, LogLevel::Error);
264 assert_eq!(messages[0].message, "error message");
265
266 assert_eq!(messages[1].level, LogLevel::Warn);
267 assert_eq!(messages[1].message, "warning message");
268
269 assert_eq!(messages[2].level, LogLevel::Info);
270 assert_eq!(messages[2].message, "info message");
271
272 assert_eq!(messages[3].level, LogLevel::Debug);
273 assert_eq!(messages[3].message, "debug message");
274 }
275
276 #[test]
277 fn test_capturing_logger_clear() {
278 let logger = CapturingLogger::new();
279
280 logger.info("message 1");
281 logger.info("message 2");
282 assert_eq!(logger.messages().len(), 2);
283
284 logger.clear();
285 assert_eq!(logger.messages().len(), 0);
286
287 logger.info("message 3");
288 assert_eq!(logger.messages().len(), 1);
289 }
290
291 #[test]
292 fn test_log_level_display() {
293 assert_eq!(format!("{}", LogLevel::Error), "ERROR");
294 assert_eq!(format!("{}", LogLevel::Warn), "WARN");
295 assert_eq!(format!("{}", LogLevel::Info), "INFO");
296 assert_eq!(format!("{}", LogLevel::Debug), "DEBUG");
297 }
298}