1use crate::datex_values::Value;
2
3use super::color::{Color, AnsiCodes};
4
5pub struct Logger<'a> {
6 name: String,
7 is_production: bool,
8 formatting: LogFormatting,
9 context: &'a LoggerContext
10}
11
12#[derive(Clone, Copy)]
13pub enum LogLevel {
14 VERBOSE,
15 DEFAULT,
16 WARNING,
17 ERROR,
18}
19
20#[derive(PartialEq)]
21pub enum LogFormatting {
22 PlainText,
23 Color4Bit,
24 ColorRGB
25}
26
27pub struct LoggerContext {
28 pub log_redirect: Option<fn(&str)->()>
29}
30
31static DEVELOPMENT_LOG_LEVEL:u8 = LogLevel::VERBOSE as u8;
32static PRODUCTION_LOG_LEVEL:u8 = LogLevel::VERBOSE as u8;
33
34
35impl Logger<'_> {
36
37
38 pub fn new<'a>(context: &'a LoggerContext, name:&'a str, is_production:bool, formatting:LogFormatting) -> Logger<'a> {
39 return Logger {name:(*name).to_string(), is_production, formatting, context}
40 }
41 pub fn new_for_production<'a>(context: &'a LoggerContext, name:&'a str) -> Logger<'a> {
42 return Logger {name:(*name).to_string(), is_production:true, formatting:LogFormatting::ColorRGB, context}
43 }
44 pub fn new_for_development<'a>(context: &'a LoggerContext, name:&'a str) -> Logger<'a> {
45 return Logger {name:(*name).to_string(), is_production:false, formatting:LogFormatting::ColorRGB, context}
46 }
47
48
49
50 fn log(&self, text:&str, data: &Vec<Box<dyn Value>>, color:Color, log_level:LogLevel, only_log_own_stream:bool, add_tag:bool) {
51 if !self.log_level_allowed(log_level.clone()) {return}
52
53 let formatted = self.generate_log_string(text, data, color, add_tag);
54 self.log_raw(&formatted, log_level, only_log_own_stream);
55 }
56
57 fn generate_log_string(&self, text:&str, _data: &Vec<Box<dyn Value>>, color:Color, add_tag:bool) -> String {
58 let message = text;
59 let end = if self.formatting == LogFormatting::PlainText {""} else {AnsiCodes::RESET};
60
61 if add_tag {format!("{}{}{}", self.get_tag(color), message, end)}
62 else {format!("{}{}", message, end)}
63 }
64
65 fn log_raw(&self, text:&str, log_level:LogLevel, _only_log_own_stream:bool) {
66
67 if !self.log_level_allowed(log_level) {return}
68
69
70 let handler = self.context.log_redirect;
71
72 if handler.is_some() {(handler.as_ref().unwrap())(text)}
74 else {println!("{}", text)}
76 }
77
78 fn log_level_allowed(&self, log_level:LogLevel) -> bool {
80 let log_level_u8 = log_level as u8;
81
82 if self.is_production && (log_level_u8 < PRODUCTION_LOG_LEVEL) {false} else if !self.is_production && (log_level_u8 < DEVELOPMENT_LOG_LEVEL) {false} else {true}
85 }
86
87 fn get_tag(&self, color:Color) -> String {
88 let color_esc = self.get_formatting_color(color);
89 let mut tag = "".to_string();
90
91 let esc_tag = self.formatting != LogFormatting::PlainText;
93
94 if esc_tag {
96 let end = if self.formatting == LogFormatting::ColorRGB {AnsiCodes::BOLD.to_string()} else {"".to_string()};
97 tag += &format!("{}{}{}{}{}", AnsiCodes::INVERSE, AnsiCodes::UNDERLINE, self.get_formatting_color_bg(Color::BLACK), color_esc, end);
98 }
99
100 if self.formatting == LogFormatting::PlainText {tag += &format!("[{}]", self.name)}
101 else {tag += &format!(" {} ", self.name)}
102
103 if esc_tag {tag += &format!("{} {}", AnsiCodes::RESET, color_esc)}
114
115 return tag;
116 }
117
118 fn get_formatting_color(&self, color:Color) -> String {
119 if self.formatting == LogFormatting::Color4Bit {return color.as_ansi_4_bit().to_string()}
120 else if self.formatting == LogFormatting::ColorRGB {return color.as_ansi_rgb()}
121 else if self.formatting == LogFormatting::PlainText {return "".to_string()}
122 else {return AnsiCodes::COLOR_DEFAULT.to_string()}
123 }
124
125 fn get_formatting_color_bg(&self, color:Color) -> String {
126 if self.formatting == LogFormatting::Color4Bit {return color.as_ansi_4_bit_bg().to_string()}
127 else if self.formatting == LogFormatting::ColorRGB {return color.as_ansi_rgb_bg()}
128 else if self.formatting == LogFormatting::PlainText {return "".to_string()}
129 else {return AnsiCodes::COLOR_DEFAULT.to_string()}
130 }
131
132 pub fn success(&self, message:&str) {
135 self.log(message, &Vec::new(), Color::GREEN, LogLevel::DEFAULT, false, true);
136 }
137
138 pub fn error(&self, message:&str) {
139 self.log(message, &Vec::new(), Color::RED, LogLevel::ERROR, false, true);
140 }
141
142 pub fn warn(&self, message:&str) {
143 self.log(message, &Vec::new(), Color::YELLOW, LogLevel::WARNING, false, true);
144 }
145
146 pub fn info(&self, message:&str) {
147 self.log(message, &Vec::new(), Color::DEFAULT, LogLevel::DEFAULT, false, true);
148 }
149
150 pub fn debug(&self, message:&str) {
151 self.log(message, &Vec::new(), Color::CYAN, LogLevel::VERBOSE, false, true);
152 }
153
154 pub fn plain(&self, message:&str) {
155 self.log(message, &Vec::new(), Color::WHITE, LogLevel::DEFAULT, false, false);
156 }
157}