xref: /DragonOS/kernel/src/libs/printk.rs (revision bd70d2d1f490aabd570a5301b858bd5eb04149fa)
1 use core::{
2     fmt::{self, Write},
3     sync::atomic::Ordering,
4 };
5 
6 use alloc::string::ToString;
7 use log::{info, Level, Log};
8 
9 use super::lib_ui::textui::{textui_putstr, FontColor};
10 
11 use crate::{
12     driver::tty::{
13         tty_driver::TtyOperation, tty_port::tty_port,
14         virtual_terminal::virtual_console::CURRENT_VCNUM,
15     },
16     filesystem::procfs::{
17         kmsg::KMSG,
18         log::{LogLevel, LogMessage},
19     },
20     time::PosixTimeSpec,
21 };
22 
23 #[macro_export]
24 macro_rules! print {
25     ($($arg:tt)*) => ($crate::libs::printk::__printk(format_args!($($arg)*)));
26 }
27 
28 #[macro_export]
29 macro_rules! println {
30     () => {
31         $crate::print!("\n");
32     };
33     ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
34 }
35 
36 pub struct PrintkWriter;
37 
38 impl PrintkWriter {
39     #[inline]
40     pub fn __write_fmt(&mut self, args: fmt::Arguments) {
41         self.write_fmt(args).ok();
42     }
43 
44     /// 并输出白底黑字
45     /// @param str: 要写入的字符
46     pub fn __write_string(&mut self, s: &str) {
47         let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst);
48         if current_vcnum != -1 {
49             // tty已经初始化了之后才输出到屏幕
50             let port = tty_port(current_vcnum as usize);
51             let tty = port.port_data().internal_tty();
52             if let Some(tty) = tty {
53                 let _ = tty.write(tty.core(), s.as_bytes(), s.len());
54             } else {
55                 let _ = textui_putstr(s, FontColor::WHITE, FontColor::BLACK);
56             }
57         } else {
58             let _ = textui_putstr(s, FontColor::WHITE, FontColor::BLACK);
59         }
60     }
61 }
62 
63 /// 为Printk Writer实现core::fmt::Write, 使得能够借助Rust自带的格式化组件,格式化字符并输出
64 impl fmt::Write for PrintkWriter {
65     fn write_str(&mut self, s: &str) -> fmt::Result {
66         self.__write_string(s);
67         Ok(())
68     }
69 }
70 
71 #[doc(hidden)]
72 pub fn __printk(args: fmt::Arguments) {
73     PrintkWriter.write_fmt(args).unwrap();
74 }
75 
76 pub struct Logger;
77 
78 impl Logger {
79     pub fn log(&self, log_level: usize, message: fmt::Arguments) {
80         if unsafe { KMSG.is_some() } {
81             let timestamp: PosixTimeSpec = PosixTimeSpec::now_cpu_time();
82             let log_level = LogLevel::from(log_level);
83 
84             let log_message = LogMessage::new(timestamp, log_level, message.to_string());
85 
86             unsafe { KMSG.as_ref().unwrap().lock_irqsave().push(log_message) };
87         }
88     }
89 }
90 
91 /// 内核自定义日志器
92 ///
93 /// todo: https://github.com/DragonOS-Community/DragonOS/issues/762
94 struct KernelLogger;
95 
96 impl Log for KernelLogger {
97     fn enabled(&self, _metadata: &log::Metadata) -> bool {
98         // 这里可以自定义日志过滤规则
99         true
100     }
101 
102     fn log(&self, record: &log::Record) {
103         if self.enabled(record.metadata()) {
104             // todo: 接入kmsg
105             Self::kernel_log(record);
106             Self::iodisplay(record)
107         }
108     }
109 
110     fn flush(&self) {
111         // 如果需要的话,可以在这里实现缓冲区刷新逻辑
112     }
113 }
114 
115 impl KernelLogger {
116     fn iodisplay(record: &log::Record) {
117         match record.level() {
118             Level::Debug | Level::Info | Level::Trace => {
119                 write!(PrintkWriter, "[ {} ] ", record.level(),)
120             }
121             Level::Error => {
122                 write!(PrintkWriter, "\x1B[41m[ ERROR ] \x1B[0m",)
123             }
124             Level::Warn => {
125                 write!(PrintkWriter, "\x1B[1;33m[ WARN ] \x1B[0m",)
126             }
127         }
128         .unwrap();
129         writeln!(
130             PrintkWriter,
131             "({}:{})\t {}",
132             record.file().unwrap_or(""),
133             record.line().unwrap_or(0),
134             record.args()
135         )
136         .unwrap();
137     }
138 
139     fn kernel_log(record: &log::Record) {
140         match record.level() {
141             Level::Debug => Logger.log(
142                 7,
143                 format_args!(
144                     "({}:{})\t {}\n",
145                     record.file().unwrap_or(""),
146                     record.line().unwrap_or(0),
147                     record.args()
148                 ),
149             ),
150             Level::Error => Logger.log(
151                 3,
152                 format_args!(
153                     "({}:{})\t {}\n",
154                     record.file().unwrap_or(""),
155                     record.line().unwrap_or(0),
156                     record.args()
157                 ),
158             ),
159             Level::Info => Logger.log(
160                 6,
161                 format_args!(
162                     "({}:{})\t {}\n",
163                     record.file().unwrap_or(""),
164                     record.line().unwrap_or(0),
165                     record.args()
166                 ),
167             ),
168             Level::Warn => Logger.log(
169                 4,
170                 format_args!(
171                     "({}:{})\t {}\n",
172                     record.file().unwrap_or(""),
173                     record.line().unwrap_or(0),
174                     record.args()
175                 ),
176             ),
177             Level::Trace => {
178                 todo!()
179             }
180         }
181     }
182 }
183 
184 pub fn early_init_logging() {
185     log::set_logger(&KernelLogger).unwrap();
186     log::set_max_level(log::LevelFilter::Debug);
187     info!("Logging initialized");
188 }
189