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