1use core::fmt;
2
3use anstyle::AnsiColor;
4use log::{Level, LevelFilter, Metadata, Record};
5
6struct KernelLogger;
8
9impl log::Log for KernelLogger {
10 fn enabled(&self, _: &Metadata<'_>) -> bool {
11 true
12 }
13
14 fn flush(&self) {
15 }
17
18 fn log(&self, record: &Record<'_>) {
19 if self.enabled(record.metadata()) {
20 println!(
21 "[{}][{}] {}",
22 crate::arch::core_local::core_id(),
23 ColorLevel(record.level()),
24 record.args()
25 );
26 }
27 }
28}
29
30struct ColorLevel(Level);
31
32impl fmt::Display for ColorLevel {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 let level = self.0;
35
36 if no_color() {
37 write!(f, "{level}")
38 } else {
39 let color = match level {
40 Level::Trace => AnsiColor::Magenta,
41 Level::Debug => AnsiColor::Blue,
42 Level::Info => AnsiColor::Green,
43 Level::Warn => AnsiColor::Yellow,
44 Level::Error => AnsiColor::Red,
45 };
46
47 let style = anstyle::Style::new().fg_color(Some(color.into()));
48 write!(f, "{style}{level}{style:#}")
49 }
50 }
51}
52
53fn no_color() -> bool {
54 option_env!("NO_COLOR").is_some_and(|val| !val.is_empty())
55}
56
57pub unsafe fn init() {
58 log::set_logger(&KernelLogger).expect("Can't initialize logger");
59 let log_level: Option<&'static str> = option_env!("HERMIT_LOG_LEVEL_FILTER");
61 let mut max_level = LevelFilter::Info;
62
63 if let Some(log_level) = log_level {
64 max_level = if log_level.eq_ignore_ascii_case("off") {
65 LevelFilter::Off
66 } else if log_level.eq_ignore_ascii_case("error") {
67 LevelFilter::Error
68 } else if log_level.eq_ignore_ascii_case("warn") {
69 LevelFilter::Warn
70 } else if log_level.eq_ignore_ascii_case("info") {
71 LevelFilter::Info
72 } else if log_level.eq_ignore_ascii_case("debug") {
73 LevelFilter::Debug
74 } else if log_level.eq_ignore_ascii_case("trace") {
75 LevelFilter::Trace
76 } else {
77 error!("Could not parse HERMIT_LOG_LEVEL_FILTER, falling back to `info`.");
78 LevelFilter::Info
79 };
80 }
81
82 log::set_max_level(max_level);
83}
84
85#[cfg(any(not(target_arch = "riscv64"), feature = "pci", feature = "tcp"))]
86macro_rules! infoheader {
87 ($str:expr) => {{
94 ::log::info!("");
95 ::log::info!("{:=^70}", $str);
96 }};
97}
98
99#[cfg_attr(target_arch = "riscv64", allow(unused))]
100macro_rules! infoentry {
101 ($str:expr, $rhs:expr) => (infoentry!($str, "{}", $rhs));
102 ($str:expr, $($arg:tt)+) => (::log::info!("{:25}{}", concat!($str, ":"), format_args!($($arg)+)));
103}
104
105#[cfg(any(not(target_arch = "riscv64"), feature = "pci", feature = "tcp"))]
106macro_rules! infofooter {
107 () => {{
108 ::log::info!("{:=^70}", '=');
109 ::log::info!("");
110 }};
111}