devalang_wasm/tools/logger/
mod.rs1#[cfg(feature = "cli")]
2use crossterm::style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor};
3#[cfg(feature = "cli")]
4use std::fmt::Write;
5
6pub mod rule_checker;
7pub use rule_checker::{RuleChecker, RuleMessage};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum LogLevel {
11 Success,
12 Error,
13 Info,
14 Warning,
15 Watch,
16 Debug,
17 Print,
18 Action,
19}
20
21#[derive(Debug, Clone, Default)]
22pub struct Logger;
23
24impl Logger {
25 pub fn new() -> Self {
26 Self
27 }
28
29 pub fn log_rule_message(&self, rule_msg: &RuleMessage) {
31 match rule_msg.level {
32 crate::platform::config::RuleLevel::Error => {
33 self.error(&rule_msg.formatted());
34 }
35 crate::platform::config::RuleLevel::Warning => {
36 self.warn(&rule_msg.formatted());
37 }
38 crate::platform::config::RuleLevel::Info => {
39 self.info(&rule_msg.formatted());
40 }
41 crate::platform::config::RuleLevel::Off => {
42 }
44 }
45 }
46
47 pub fn log(&self, level: LogLevel, message: impl AsRef<str>) {
48 self.print_line(level, message.as_ref());
49 }
50
51 pub fn log_with_details<I, S>(&self, level: LogLevel, message: impl AsRef<str>, details: I)
52 where
53 I: IntoIterator<Item = S>,
54 S: AsRef<str>,
55 {
56 self.print_line(level, message.as_ref());
57 for detail in details {
58 self.print_detail(detail.as_ref());
59 }
60 }
61
62 pub fn log_structured_error(&self, error: &StructuredError) {
64 self.log(LogLevel::Error, &error.message);
65 let colored_details = error.build_colored_details();
66 for (label, content) in colored_details {
67 self.print_colored_detail(&label, &content);
68 }
69 }
70
71 pub fn success(&self, message: impl AsRef<str>) {
72 self.log(LogLevel::Success, message);
73 }
74
75 pub fn info(&self, message: impl AsRef<str>) {
76 self.log(LogLevel::Info, message);
77 }
78
79 pub fn warn(&self, message: impl AsRef<str>) {
80 self.log(LogLevel::Warning, message);
81 }
82
83 pub fn error(&self, message: impl AsRef<str>) {
84 self.log(LogLevel::Error, message);
85 }
86
87 pub fn watch(&self, message: impl AsRef<str>) {
88 self.log(LogLevel::Watch, message);
89 }
90
91 pub fn debug(&self, message: impl AsRef<str>) {
92 self.log(LogLevel::Debug, message);
93 }
94
95 pub fn action(&self, message: impl AsRef<str>) {
96 self.log(LogLevel::Action, message);
97 }
98
99 pub fn print(&self, message: impl AsRef<str>) {
102 self.log(LogLevel::Print, message);
103 }
104
105 fn print_detail(&self, detail: &str) {
106 #[cfg(feature = "cli")]
107 {
108 println!(" ↳ {}", detail);
109 }
110 #[cfg(not(feature = "cli"))]
111 {
112 println!(" -> {}", detail);
113 }
114 }
115
116 #[cfg(feature = "cli")]
119 fn print_colored_detail(&self, label: &str, content: &str) {
120 let mut output = String::new();
121 output.push_str(" ↳ ");
122
123 output.push_str(&format!(
125 "{}{}{}{}",
126 SetForegroundColor(Color::Rgb {
127 r: 110,
128 g: 110,
129 b: 110
130 }),
131 SetAttribute(Attribute::Bold),
132 label,
133 SetAttribute(Attribute::Reset)
134 ));
135
136 output.push_str(": ");
138
139 output.push_str(&format!("{}{}", SetForegroundColor(Color::White), content));
141
142 output.push_str(&format!("{}", ResetColor));
143
144 println!("{}", output);
145 }
146
147 #[cfg(not(feature = "cli"))]
149 fn print_colored_detail(&self, label: &str, content: &str) {
150 println!(" -> {}: {}", label, content);
151 }
152
153 fn print_line(&self, level: LogLevel, message: &str) {
154 #[cfg(feature = "cli")]
155 {
156 println!("{}", self.render_colored_line(level, message));
157 }
158 #[cfg(not(feature = "cli"))]
159 {
160 println!("[{}] {}", level.as_plain_label(), message);
161 }
162 }
163
164 #[cfg(feature = "cli")]
165 fn render_colored_line(&self, level: LogLevel, message: &str) -> String {
166 let mut out = String::new();
167 let (emoji, color) = level.visuals();
168
169 out.push_str(emoji);
170 out.push(' ');
171 out.push_str(&self.render_signature());
172 out.push(' ');
173 out.push_str(&self.render_status(level, color));
174 out.push(' ');
175 out.push_str(message);
176 out
177 }
178
179 #[cfg(feature = "cli")]
180 fn render_signature(&self) -> String {
181 let mut s = String::new();
182 write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
183 s.push('[');
184 write!(
185 &mut s,
186 "{}",
187 SetForegroundColor(Color::Rgb {
188 r: 36,
189 g: 199,
190 b: 181,
191 })
192 )
193 .unwrap();
194 write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
195 s.push_str("Devalang");
196 write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
197 write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
198 s.push(']');
199 write!(&mut s, "{}", ResetColor).unwrap();
200 s
201 }
202
203 #[cfg(feature = "cli")]
204 fn render_status(&self, level: LogLevel, color: Color) -> String {
205 let mut s = String::new();
206 write!(&mut s, "{}", SetForegroundColor(color)).unwrap();
207 write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
208 s.push('[');
209 s.push_str(level.as_label());
210 s.push(']');
211 write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
212 write!(&mut s, "{}", ResetColor).unwrap();
213 s
214 }
215}
216
217impl LogLevel {
218 fn as_label(self) -> &'static str {
219 match self {
220 LogLevel::Success => "SUCCESS",
221 LogLevel::Error => "ERROR",
222 LogLevel::Info => "INFO",
223 LogLevel::Warning => "WARN",
224 LogLevel::Watch => "WATCH",
225 LogLevel::Debug => "DEBUG",
226 LogLevel::Action => "ACTION",
227 LogLevel::Print => "PRINT",
228 }
229 }
230
231 fn as_plain_label(self) -> &'static str {
232 match self {
233 LogLevel::Success => "SUCCESS",
234 LogLevel::Error => "ERROR",
235 LogLevel::Info => "INFO",
236 LogLevel::Warning => "WARN",
237 LogLevel::Watch => "WATCH",
238 LogLevel::Debug => "DEBUG",
239 LogLevel::Action => "ACTION",
240 LogLevel::Print => "PRINT",
241 }
242 }
243
244 #[cfg(feature = "cli")]
245 fn visuals(self) -> (&'static str, Color) {
246 match self {
247 LogLevel::Success => (
248 "✅",
249 Color::Rgb {
250 r: 76,
251 g: 175,
252 b: 80,
253 },
254 ),
255 LogLevel::Error => (
256 "❌",
257 Color::Rgb {
258 r: 244,
259 g: 67,
260 b: 54,
261 },
262 ),
263 LogLevel::Info => (
264 "ℹ️ ",
265 Color::Rgb {
266 r: 33,
267 g: 150,
268 b: 243,
269 },
270 ),
271 LogLevel::Warning => (
272 "⚠️",
273 Color::Rgb {
274 r: 255,
275 g: 152,
276 b: 0,
277 },
278 ),
279 LogLevel::Watch => (
280 "👀",
281 Color::Rgb {
282 r: 171,
283 g: 71,
284 b: 188,
285 },
286 ),
287 LogLevel::Debug => (
288 "🛠️",
289 Color::Rgb {
290 r: 121,
291 g: 134,
292 b: 203,
293 },
294 ),
295 LogLevel::Action => (
296 "🎵",
297 Color::Rgb {
298 r: 0,
299 g: 188,
300 b: 212,
301 },
302 ),
303 LogLevel::Print => ("", Color::White),
304 }
305 }
306}
307
308pub mod format;
309pub mod layers;
310pub mod sinks;
311pub mod structured_error;
312
313pub use structured_error::StructuredError;