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