1#![no_std]
2
3extern crate alloc;
4
5use alloc::fmt;
6use log_external::Log;
7use log_external::Metadata;
8pub use log_external::Record;
9pub use log_external::debug as Debug;
10pub use log_external::error as Error;
11pub use log_external::info as Information;
12use log_external::set_logger;
13use log_external::set_max_level;
14pub use log_external::trace as Trace;
15pub use log_external::warn as Warning;
16use synchronization::once_lock::OnceLock;
17
18const BOLD: &str = "\x1b[0;1m";
19const RED: &str = "\x1b[0;41m";
20const YELLOW: &str = "\x1b[0;43m";
21const BLUE: &str = "\x1b[0;46m";
22const GREEN: &str = "\x1b[0;42m";
23const GREY: &str = "\x1b[0;100m";
24const RESET: &str = "\x1b[0m";
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Level {
28 Error = 1,
29 Warn,
30 Info,
31 Debug,
32 Trace,
33}
34
35impl From<log_external::Level> for Level {
36 fn from(level: log_external::Level) -> Self {
37 match level {
38 log_external::Level::Error => Level::Error,
39 log_external::Level::Warn => Level::Warn,
40 log_external::Level::Info => Level::Info,
41 log_external::Level::Debug => Level::Debug,
42 log_external::Level::Trace => Level::Trace,
43 }
44 }
45}
46
47pub trait LoggerTrait: Send + Sync {
48 fn enabled(&self, level: Level) -> bool;
49
50 fn write(&self, arguments: fmt::Arguments);
51
52 fn log(&self, record: &Record) {
53 let letter = match record.level() {
54 log_external::Level::Error => "E",
55 log_external::Level::Warn => "W",
56 log_external::Level::Info => "I",
57 log_external::Level::Debug => "D",
58 log_external::Level::Trace => "T",
59 };
60
61 let color = match record.level() {
62 log_external::Level::Error => RED,
63 log_external::Level::Warn => YELLOW,
64 log_external::Level::Info => BLUE,
65 log_external::Level::Debug => GREEN,
66 log_external::Level::Trace => GREY,
67 };
68
69 self.write(format_args!(
70 "{} {} {} | {}{}{} | {}",
71 color,
72 letter,
73 RESET,
74 BOLD,
75 record.target(),
76 RESET,
77 record.args()
78 ))
79 }
80
81 fn flush(&self) {
82 }
84}
85
86struct Logger(&'static dyn LoggerTrait);
87
88impl Log for Logger {
89 fn enabled(&self, metadata: &Metadata) -> bool {
90 self.0.enabled(Level::from(metadata.level()))
91 }
92
93 fn log(&self, record: &Record) {
94 if !self.enabled(record.metadata()) {
95 return;
96 }
97 self.0.log(record)
98 }
99
100 fn flush(&self) {
101 self.0.flush();
102 }
103}
104
105static LOGGER_INSTANCE: OnceLock<Logger> = OnceLock::new();
106
107pub fn initialize(logger: &'static dyn LoggerTrait) -> Result<(), log_external::SetLoggerError> {
108 let logger = LOGGER_INSTANCE.get_or_init(|| Logger(logger));
109
110 set_logger(logger).expect("Failed to set logger");
111 set_max_level(log_external::LevelFilter::Trace);
112 Ok(())
113}
114
115pub fn test_write(logger: &impl LoggerTrait) {
116 for i in 0..5 {
117 logger.write(format_args!("This is a test message number {i}."));
118 }
119}
120
121pub fn test_log(logger: &impl LoggerTrait) {
122 logger.log(
123 &Record::builder()
124 .level(log_external::Level::Info)
125 .args(format_args!("This is a test log message."))
126 .build(),
127 );
128 logger.log(
129 &Record::builder()
130 .level(log_external::Level::Warn)
131 .args(format_args!("This is a test warning message."))
132 .build(),
133 );
134 logger.log(
135 &Record::builder()
136 .level(log_external::Level::Error)
137 .args(format_args!("This is a test error message."))
138 .build(),
139 );
140 logger.log(
141 &Record::builder()
142 .level(log_external::Level::Debug)
143 .args(format_args!("This is a test debug message."))
144 .build(),
145 );
146 logger.log(
147 &Record::builder()
148 .level(log_external::Level::Trace)
149 .args(format_args!("This is a test trace message."))
150 .build(),
151 );
152}
153
154pub fn test_flush(logger: &impl LoggerTrait) {
155 logger.flush();
156}