sel4_logging/
lib.rs
1#![no_std]
8
9use core::fmt::{self, Write};
10
11use log::{Log, Metadata, Record, SetLoggerError};
12
13pub use log::{self, LevelFilter};
14
15mod synchronized;
16
17pub use synchronized::SynchronizedLogger;
18
19pub struct Logger {
20 pub level_filter: LevelFilter,
21 pub filter: fn(&Metadata) -> bool,
22 pub fmt: FmtRecordFn,
23 pub write: fn(&str),
24 pub flush: fn(),
25}
26
27pub type FmtRecordFn = fn(&Record, &mut fmt::Formatter) -> fmt::Result;
28
29pub const FMT_RECORD_DEFAULT: FmtRecordFn = fmt_with_module;
30
31impl Logger {
32 pub const fn const_default() -> Self {
33 Self {
34 level_filter: LevelFilter::Warn,
35 filter: |_| true,
36 fmt: FMT_RECORD_DEFAULT,
37 write: |_| (),
38 flush: || (),
39 }
40 }
41
42 pub fn level_filter(&self) -> LevelFilter {
43 self.level_filter
44 }
45
46 pub fn set_max_level(&self) {
47 log::set_max_level(self.level_filter());
48 }
49
50 pub fn set(&'static self) -> Result<(), SetLoggerError> {
51 self.set_max_level();
52 log::set_logger(self)?;
53 Ok(())
54 }
55}
56
57impl Log for Logger {
58 fn enabled(&self, metadata: &Metadata) -> bool {
59 metadata.level() <= self.level_filter && (self.filter)(metadata)
60 }
61
62 fn log(&self, record: &Record) {
63 if self.enabled(record.metadata()) {
64 let mut writer = WriteWrapper(self.write);
65 let wrapped = DisplayWrapper {
66 fmt: self.fmt,
67 record,
68 };
69 writeln!(writer, "{wrapped}").unwrap()
70 }
71 }
72
73 fn flush(&self) {
74 (self.flush)()
75 }
76}
77
78struct WriteWrapper(fn(&str));
81
82impl fmt::Write for WriteWrapper {
83 fn write_str(&mut self, s: &str) -> fmt::Result {
84 (self.0)(s);
85 Ok(())
86 }
87}
88
89struct DisplayWrapper<'a> {
90 fmt: FmtRecordFn,
91 record: &'a Record<'a>,
92}
93
94impl fmt::Display for DisplayWrapper<'_> {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 (self.fmt)(self.record, f)
97 }
98}
99
100pub struct LoggerBuilder(Logger);
103
104impl LoggerBuilder {
105 pub const fn const_default() -> Self {
106 Self(Logger::const_default())
107 }
108
109 pub const fn build(self) -> Logger {
110 self.0
111 }
112
113 pub const fn level_filter(mut self, level_filter: LevelFilter) -> Self {
114 self.0.level_filter = level_filter;
115 self
116 }
117
118 pub const fn filter(mut self, filter: fn(&Metadata) -> bool) -> Self {
119 self.0.filter = filter;
120 self
121 }
122
123 pub const fn fmt(mut self, fmt: FmtRecordFn) -> Self {
124 self.0.fmt = fmt;
125 self
126 }
127
128 pub const fn write(mut self, write: fn(&str)) -> Self {
129 self.0.write = write;
130 self
131 }
132
133 pub const fn flush(mut self, flush: fn()) -> Self {
134 self.0.flush = flush;
135 self
136 }
137}
138
139pub fn fmt_with_module(record: &Record, f: &mut fmt::Formatter) -> fmt::Result {
142 let target = if !record.target().is_empty() {
143 record.target()
144 } else {
145 record.module_path().unwrap_or_default()
146 };
147 write!(f, "{:<5} [{}] {}", record.level(), target, record.args())
148}
149
150pub fn fmt_with_line(record: &Record, f: &mut fmt::Formatter) -> fmt::Result {
151 write!(f, "{:<5} [", record.level())?;
152 if let Some(file) = record.file() {
153 write!(f, "{file}")?;
154 } else if let Some(file) = record.file_static() {
155 write!(f, "{file}")?;
156 } else {
157 write!(f, "(?)")?;
158 }
159 write!(f, ":")?;
160 if let Some(line) = record.line() {
161 write!(f, "{line}")?;
162 } else {
163 write!(f, "(?)")?;
164 }
165 write!(f, "] {}", record.args())
166}