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
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 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;