1use std::time::SystemTime;
30
31use chrono::{ DateTime, Utc };
32
33
34use super::node_tree_base::NodeIdentity;
35use crate::prelude::{ RID, NodeTreeBase };
36use crate::utils::functions::draw_tree;
37
38
39#[derive(Debug, Clone)]
47pub enum LoggerVerbosity {
48 All,
49 NoDebug,
50 OnlyIssues,
51 OnlyPanics
52}
53
54
55#[derive(Debug, Clone)]
57pub enum SystemCall {
58 Named(String),
59 NodePath(String)
60}
61
62impl SystemCall {
63
64 pub fn format(&self) -> String {
66 match self {
67 Self::Named(str) => str.to_string(),
68 Self::NodePath(str) => format!("[{}]", str)
69 }
70 }
71
72 pub fn to_str(&self) -> &str {
74 match self {
75 Self::Named(str) => str,
76 Self::NodePath(str) => str
77 }
78 }
79}
80
81
82#[derive(Debug, Clone)]
84pub enum Log<'a> {
85 Debug(&'a str),
86 Info(&'a str),
87 Warn(&'a str),
88 Panic(&'a str)
89}
90
91impl <'a >Log<'a> {
92
93 pub fn get_lv(&self) -> String {
95 match self {
96 Log::Debug(_) => "DEBUG".to_string(),
97 Log::Info(_) => "INFO".to_string(),
98 Log::Warn(_) => "WARN".to_string(),
99 Log::Panic(_) => "PANIC!".to_string()
100 }
101 }
102
103 pub fn get_msg(&self) -> &'a str {
105 match self {
106 Log::Debug(str) => str,
107 Log::Info(str) => str,
108 Log::Warn(str) => str,
109 Log::Panic(str) => str
110 }
111 }
112
113 pub fn get_colour(&self) -> String {
115 match self {
116 Log::Debug(_) => "\u{001b}[30m".to_string(), Log::Info(_) => "\u{001b}[37m".to_string(), Log::Warn(_) => "\u{001b}[33m".to_string(), Log::Panic(_) => "\u{001b}[31m".to_string() }
121 }
122
123 pub fn is_debug(&self) -> bool {
125 match self {
126 Log::Debug(_) => true,
127 _ => false
128 }
129 }
130
131 pub fn is_problematic(&self) -> bool {
133 match self {
134 Log::Warn(_) | Log::Panic(_) => true,
135 _ => false
136 }
137 }
138
139 pub fn is_panic(&self) -> bool {
141 match self {
142 Log::Panic(_) => true,
143 _ => false
144 }
145 }
146}
147
148
149#[derive(Debug, Clone)]
156pub struct Logger {
157 log: String,
158 verbosity_lv: LoggerVerbosity,
159 crash_header: String,
160 crash_footer: String
161}
162
163impl Logger {
164
165 pub fn new(verbosity_lv: LoggerVerbosity) -> Self {
167 let mut logger: Logger = Logger {
168 log: String::new(),
169 verbosity_lv,
170 crash_header: "Unfortunately the program has crashed. Please contact the development team with the following crash report as well as the attachment of the log posted during the time of the crash.".to_string(),
171 crash_footer: "Goodbye World! (Program Exited)".to_string()
172 };
173
174 logger.post_manual(SystemCall::Named("SysLogger".to_string()), Log::Debug("System logger has initialized. Hello World!"));
175 logger
176 }
177
178 pub fn set_default_header_on_panic(&mut self, msg: &str) {
180 self.crash_header = msg.to_string();
181 }
182
183 pub fn set_default_footer_on_panic(&mut self, msg: &str) {
185 self.crash_footer = msg.to_string();
186 }
187
188 pub unsafe fn post(&mut self, calling: RID, log: Log, node_tree: *mut NodeTreeBase) -> bool {
194 match &self.verbosity_lv {
195 LoggerVerbosity::All => {},
196 LoggerVerbosity::NoDebug => if log.is_debug() { return false; },
197 LoggerVerbosity::OnlyIssues => if !log.is_problematic() { return false; },
198 LoggerVerbosity::OnlyPanics => if !log.is_panic() { return false; }
199 }
200
201 let node_tree: &NodeTreeBase = &*node_tree;
202 let system: SystemCall = {
203 match node_tree.get_node_identity(calling) {
204 Some(NodeIdentity::NodePath) => SystemCall::NodePath(unsafe { node_tree.get_node(calling).unwrap_unchecked() }.get_absolute_path().to_string()),
205 Some(NodeIdentity::UniqueName(name)) => SystemCall::Named(name),
206 None => unimplemented!()
207 }
208 };
209
210 let colour: String = log.get_colour();
211 let panic: bool = log.is_panic();
212 let time: String = self.post_manual(system, log);
213
214 if panic {
215 let node_tree_visual: String = draw_tree(node_tree, calling, 6, 6);
216 println!("
217{}{}
218
219\u{001b}[0m{}{}
220Time of Crash: {}
221Exit Code: {}
222
223{}\u{001b}[0m", colour, self.crash_header, node_tree_visual, colour, time, 1, self.crash_footer);
224
225 self.log += &format!("
226{}
227
228{}
229Time of Crash: {}
230Exit Code: {}
231
232{}", self.crash_header, node_tree_visual, time, 1, self.crash_footer);
233 }
234
235 panic
236 }
237
238 pub fn post_manual(&mut self, system: SystemCall, log: Log) -> String {
241 let time: String = DateTime::<Utc>::from(SystemTime::now()).format("%d/%m/%Y %T").to_string();
242 match &self.verbosity_lv {
243 LoggerVerbosity::All => {},
244 LoggerVerbosity::NoDebug => if log.is_debug() { return time; },
245 LoggerVerbosity::OnlyIssues => if !log.is_problematic() { return time; },
246 LoggerVerbosity::OnlyPanics => if !log.is_panic() { return time; }
247 }
248
249 println!(
250 "{}<{} UTC> | {} | {} | {}\u{001b}[0m",
251 log.get_colour(),
252 time,
253 system.format(),
254 log.get_lv(),
255 log.get_msg()
256 );
257
258 self.log += &format!(
259 "<{} UTC> | {} | {} | {}\n",
260 time,
261 system.format(),
262 log.get_lv(),
263 log.get_msg()
264 );
265
266 time
267 }
268
269 pub fn to_str(&self) -> &str {
271 &self.log
272 }
273}
274
275
276#[macro_export]
289macro_rules! debug {
290 ($self:ident, $fmt_str:literal) => {{
291 $self.post(Log::Debug(&format!($fmt_str)))
292 }};
293
294 ($self:ident, $fmt_str:literal, $($args:expr),*) => {{
295 $self.post(Log::Debug(&format!($fmt_str, $($args),*)))
296 }};
297}
298
299#[macro_export]
306macro_rules! info {
307 ($self:ident, $fmt_str:literal) => {{
308 $self.post(Log::Info(&format!($fmt_str)))
309 }};
310
311 ($self:ident, $fmt_str:literal, $($args:expr),*) => {{
312 $self.post(Log::Info(&format!($fmt_str, $($args),*)))
313 }};
314}
315
316#[macro_export]
323macro_rules! warn {
324 ($self:ident, $fmt_str:literal) => {{
325 $self.post(Log::Warn(&format!($fmt_str)))
326 }};
327
328 ($self:ident, $fmt_str:literal, $($args:expr),*) => {{
329 $self.post(Log::Warn(&format!($fmt_str, $($args),*)))
330 }};
331}
332
333#[macro_export]
340macro_rules! error {
341 ($self:ident, $fmt_str:literal) => {{
342 $self.post(Log::Panic(&format!($fmt_str)))
343 }};
344
345 ($self:ident, $fmt_str:literal, $($args:expr),*) => {{
346 $self.post(Log::Panic(&format!($fmt_str, $($args),*)))
347 }};
348}