1use crate::context::Context;
2
3pub const INFO: &str = "INFO";
4pub const WARN: &str = "WARN";
5pub const ERROR: &str = "ERROR";
6
7const MAX_SEVERITY_LENGTH: usize = 5;
8
9#[derive(Clone, Debug)]
10pub struct DefaultLogger {}
11
12pub trait Logger: Clone + std::fmt::Debug {
13 fn write(&self, msg: String);
15
16 fn info(&self, msg: impl AsRef<str>, context: Option<&Context>) {
18 self.write(self.format_log(msg, INFO, context));
19 }
20
21 fn warn(&self, msg: impl AsRef<str>, context: Option<&Context>) {
23 self.write(self.format_log(msg, WARN, context));
24 }
25
26 fn error(&self, msg: impl AsRef<str>, context: Option<&Context>) {
28 self.write(self.format_log(msg, ERROR, context));
29 }
30
31 fn format_log(&self, msg: impl AsRef<str>, level: &str, context: Option<&Context>) -> String {
33 let level_display = format!("{:0width$}", level, width = MAX_SEVERITY_LENGTH);
35 let context_label = context
36 .and_then(|c| c.label())
37 .map(|l| format!("[{}] ", l))
38 .unwrap_or_default();
39
40 let context_line = if level == "WARN" || level == "ERROR" {
42 context
43 .and_then(|c| c.display_line())
44 .map(|l| format!("\n{}", l))
45 .unwrap_or_default()
46 } else {
47 String::new()
48 };
49
50 format!(
52 "make: {level_display} {context_label}| {}{}",
53 msg.as_ref(),
54 context_line
55 )
56 }
57}
58
59impl Logger for DefaultLogger {
61 fn write(&self, msg: String) {
62 eprintln!("{}", msg);
63 }
64}