log/
lib.rs

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        // Implement flush logic if needed, e.g., flushing buffers to a file or console
83    }
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}