1#![cfg_attr(not(feature = "std"), no_std)]
43
44extern crate log;
45
46use core::{
47 fmt::{self, Write},
48 str::FromStr,
49};
50
51#[cfg(not(feature = "std"))]
52use crate_interface::call_interface;
53use log::{Level, LevelFilter, Log, Metadata, Record};
54pub use log::{debug, error, info, trace, warn};
55
56#[macro_export]
61macro_rules! ax_print {
62 ($($arg:tt)*) => {
63 $crate::__print_impl(format_args!($($arg)*));
64 }
65}
66
67#[macro_export]
69macro_rules! ax_println {
70 () => { $crate::ax_print!("\n") };
71 ($($arg:tt)*) => {
72 $crate::__print_impl(format_args!("{}\n", format_args!($($arg)*)));
73 }
74}
75
76macro_rules! with_color {
77 ($color_code:expr, $($arg:tt)*) => {
78 format_args!("\u{1B}[{}m{}\u{1B}[m", $color_code as u8, format_args!($($arg)*))
79 };
80}
81
82#[repr(u8)]
83#[allow(dead_code)]
84enum ColorCode {
85 Black = 30,
86 Red = 31,
87 Green = 32,
88 Yellow = 33,
89 Blue = 34,
90 Magenta = 35,
91 Cyan = 36,
92 White = 37,
93 BrightBlack = 90,
94 BrightRed = 91,
95 BrightGreen = 92,
96 BrightYellow = 93,
97 BrightBlue = 94,
98 BrightMagenta = 95,
99 BrightCyan = 96,
100 BrightWhite = 97,
101}
102
103#[crate_interface::def_interface]
105pub trait LogIf {
106 fn console_write_str(s: &str);
108
109 fn current_time() -> core::time::Duration;
111
112 fn current_cpu_id() -> Option<usize>;
116
117 fn current_task_id() -> Option<u64>;
121}
122
123struct Logger;
124
125impl Write for Logger {
126 fn write_str(&mut self, s: &str) -> fmt::Result {
127 cfg_if::cfg_if! {
128 if #[cfg(feature = "std")] {
129 std::print!("{s}");
130 } else {
131 call_interface!(LogIf::console_write_str, s);
132 }
133 }
134 Ok(())
135 }
136}
137
138impl Log for Logger {
139 #[inline]
140 fn enabled(&self, _metadata: &Metadata) -> bool {
141 true
142 }
143
144 fn log(&self, record: &Record) {
145 if !self.enabled(record.metadata()) {
146 return;
147 }
148
149 let level = record.level();
150 let line = record.line().unwrap_or(0);
151 let path = record.target();
152 let args_color = match level {
153 Level::Error => ColorCode::Red,
154 Level::Warn => ColorCode::Yellow,
155 Level::Info => ColorCode::Green,
156 Level::Debug => ColorCode::Cyan,
157 Level::Trace => ColorCode::BrightBlack,
158 };
159
160 cfg_if::cfg_if! {
161 if #[cfg(feature = "std")] {
162 __print_impl(with_color!(
163 ColorCode::White,
164 "[{time} {path}:{line}] {args}\n",
165 time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.6f"),
166 path = path,
167 line = line,
168 args = with_color!(args_color, "{}", record.args()),
169 ));
170 } else {
171 let cpu_id = call_interface!(LogIf::current_cpu_id);
172 let tid = call_interface!(LogIf::current_task_id);
173 let now = call_interface!(LogIf::current_time);
174 if let Some(cpu_id) = cpu_id {
175 if let Some(tid) = tid {
176 __print_impl(with_color!(
178 ColorCode::White,
179 "[{:>3}.{:06} {cpu_id}:{tid} {path}:{line}] {args}\n",
180 now.as_secs(),
181 now.subsec_micros(),
182 cpu_id = cpu_id,
183 tid = tid,
184 path = path,
185 line = line,
186 args = with_color!(args_color, "{}", record.args()),
187 ));
188 } else {
189 __print_impl(with_color!(
191 ColorCode::White,
192 "[{:>3}.{:06} {cpu_id} {path}:{line}] {args}\n",
193 now.as_secs(),
194 now.subsec_micros(),
195 cpu_id = cpu_id,
196 path = path,
197 line = line,
198 args = with_color!(args_color, "{}", record.args()),
199 ));
200 }
201 } else {
202 __print_impl(with_color!(
204 ColorCode::White,
205 "[{:>3}.{:06} {path}:{line}] {args}\n",
206 now.as_secs(),
207 now.subsec_micros(),
208 path = path,
209 line = line,
210 args = with_color!(args_color, "{}", record.args()),
211 ));
212 }
213 }
214 }
215 }
216
217 fn flush(&self) {}
218}
219
220pub fn print_fmt(args: fmt::Arguments) -> fmt::Result {
222 use kspin::SpinNoIrq; static LOCK: SpinNoIrq<()> = SpinNoIrq::new(());
224
225 let _guard = LOCK.lock();
226 Logger.write_fmt(args)
227}
228
229#[doc(hidden)]
230pub fn __print_impl(args: fmt::Arguments) {
231 print_fmt(args).unwrap();
232}
233
234pub fn init() {
239 log::set_logger(&Logger).unwrap();
240 log::set_max_level(LevelFilter::Warn);
241}
242
243pub fn set_max_level(level: &str) {
251 let lf = LevelFilter::from_str(level)
252 .ok()
253 .unwrap_or(LevelFilter::Off);
254 log::set_max_level(lf);
255}