devalang_wasm/tools/logger/
mod.rs

1#[cfg(feature = "cli")]
2use crossterm::style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor};
3#[cfg(feature = "cli")]
4use std::fmt::Write;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum LogLevel {
8    Success,
9    Error,
10    Info,
11    Warning,
12    Watch,
13    Debug,
14    Print,
15    Action,
16}
17
18#[derive(Debug, Clone, Default)]
19pub struct Logger;
20
21impl Logger {
22    pub fn new() -> Self {
23        Self
24    }
25
26    pub fn log(&self, level: LogLevel, message: impl AsRef<str>) {
27        self.print_line(level, message.as_ref());
28    }
29
30    pub fn log_with_details<I, S>(&self, level: LogLevel, message: impl AsRef<str>, details: I)
31    where
32        I: IntoIterator<Item = S>,
33        S: AsRef<str>,
34    {
35        self.print_line(level, message.as_ref());
36        for detail in details {
37            self.print_detail(detail.as_ref());
38        }
39    }
40
41    pub fn success(&self, message: impl AsRef<str>) {
42        self.log(LogLevel::Success, message);
43    }
44
45    pub fn info(&self, message: impl AsRef<str>) {
46        self.log(LogLevel::Info, message);
47    }
48
49    pub fn warn(&self, message: impl AsRef<str>) {
50        self.log(LogLevel::Warning, message);
51    }
52
53    pub fn error(&self, message: impl AsRef<str>) {
54        self.log(LogLevel::Error, message);
55    }
56
57    pub fn watch(&self, message: impl AsRef<str>) {
58        self.log(LogLevel::Watch, message);
59    }
60
61    pub fn debug(&self, message: impl AsRef<str>) {
62        self.log(LogLevel::Debug, message);
63    }
64
65    pub fn action(&self, message: impl AsRef<str>) {
66        self.log(LogLevel::Action, message);
67    }
68
69    /// Print-level messages coming from user `print` statements. Rendered as [PRINT]
70    /// in plain/CLI output. Convenience wrapper around `log`.
71    pub fn print(&self, message: impl AsRef<str>) {
72        self.log(LogLevel::Print, message);
73    }
74
75    fn print_detail(&self, detail: &str) {
76        #[cfg(feature = "cli")]
77        {
78            println!("   ↳ {}", detail);
79        }
80        #[cfg(not(feature = "cli"))]
81        {
82            println!("   -> {}", detail);
83        }
84    }
85
86    fn print_line(&self, level: LogLevel, message: &str) {
87        #[cfg(feature = "cli")]
88        {
89            println!("{}", self.render_colored_line(level, message));
90        }
91        #[cfg(not(feature = "cli"))]
92        {
93            println!("[{}] {}", level.as_plain_label(), message);
94        }
95    }
96
97    #[cfg(feature = "cli")]
98    fn render_colored_line(&self, level: LogLevel, message: &str) -> String {
99        let mut out = String::new();
100        let (emoji, color) = level.visuals();
101
102        out.push_str(emoji);
103        out.push(' ');
104        out.push_str(&self.render_signature());
105        out.push(' ');
106        out.push_str(&self.render_status(level, color));
107        out.push(' ');
108        out.push_str(message);
109        out
110    }
111
112    #[cfg(feature = "cli")]
113    fn render_signature(&self) -> String {
114        let mut s = String::new();
115        write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
116        s.push('[');
117        write!(
118            &mut s,
119            "{}",
120            SetForegroundColor(Color::Rgb {
121                r: 36,
122                g: 199,
123                b: 181,
124            })
125        )
126        .unwrap();
127        write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
128        s.push_str("Devalang");
129        write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
130        write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
131        s.push(']');
132        write!(&mut s, "{}", ResetColor).unwrap();
133        s
134    }
135
136    #[cfg(feature = "cli")]
137    fn render_status(&self, level: LogLevel, color: Color) -> String {
138        let mut s = String::new();
139        write!(&mut s, "{}", SetForegroundColor(color)).unwrap();
140        write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
141        s.push('[');
142        s.push_str(level.as_label());
143        s.push(']');
144        write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
145        write!(&mut s, "{}", ResetColor).unwrap();
146        s
147    }
148}
149
150impl LogLevel {
151    fn as_label(self) -> &'static str {
152        match self {
153            LogLevel::Success => "SUCCESS",
154            LogLevel::Error => "ERROR",
155            LogLevel::Info => "INFO",
156            LogLevel::Warning => "WARN",
157            LogLevel::Watch => "WATCH",
158            LogLevel::Debug => "DEBUG",
159            LogLevel::Action => "ACTION",
160            LogLevel::Print => "PRINT",
161        }
162    }
163
164    fn as_plain_label(self) -> &'static str {
165        match self {
166            LogLevel::Success => "SUCCESS",
167            LogLevel::Error => "ERROR",
168            LogLevel::Info => "INFO",
169            LogLevel::Warning => "WARN",
170            LogLevel::Watch => "WATCH",
171            LogLevel::Debug => "DEBUG",
172            LogLevel::Action => "ACTION",
173            LogLevel::Print => "PRINT",
174        }
175    }
176
177    #[cfg(feature = "cli")]
178    fn visuals(self) -> (&'static str, Color) {
179        match self {
180            LogLevel::Success => (
181                "✅",
182                Color::Rgb {
183                    r: 76,
184                    g: 175,
185                    b: 80,
186                },
187            ),
188            LogLevel::Error => (
189                "❌",
190                Color::Rgb {
191                    r: 244,
192                    g: 67,
193                    b: 54,
194                },
195            ),
196            LogLevel::Info => (
197                "ℹ️ ",
198                Color::Rgb {
199                    r: 33,
200                    g: 150,
201                    b: 243,
202                },
203            ),
204            LogLevel::Warning => (
205                "⚠️",
206                Color::Rgb {
207                    r: 255,
208                    g: 152,
209                    b: 0,
210                },
211            ),
212            LogLevel::Watch => (
213                "👀",
214                Color::Rgb {
215                    r: 171,
216                    g: 71,
217                    b: 188,
218                },
219            ),
220            LogLevel::Debug => (
221                "🛠️",
222                Color::Rgb {
223                    r: 121,
224                    g: 134,
225                    b: 203,
226                },
227            ),
228            LogLevel::Action => (
229                "🎵",
230                Color::Rgb {
231                    r: 0,
232                    g: 188,
233                    b: 212,
234                },
235            ),
236            LogLevel::Print => ("", Color::White),
237        }
238    }
239}
240
241pub mod format;
242pub mod layers;
243pub mod sinks;