bootmgr_rs_core/system/
log_backend.rs

1//! Simple UEFI backend for the [`log`] crate.
2
3use core::fmt::Write;
4
5use alloc::boxed::Box;
6use log::{Level, Metadata, Record};
7use uefi::{runtime, system::with_stdout};
8
9/// A simple logging backend for UEFI.
10#[derive(Default)]
11pub struct UefiLogger;
12
13impl UefiLogger {
14    /// Constructs a new [`UefiLogger`].
15    #[must_use = "Has no effect if the result is unused"]
16    pub const fn new() -> Self {
17        Self
18    }
19
20    /// Constructs a new [`UefiLogger`], then immediately leaks it so that it can be used with `set_logger`.
21    ///
22    /// This is a possibly simpler alternative to using a global static logger.
23    #[must_use = "Has no effect if the result is unused"]
24    pub fn static_new() -> &'static Self {
25        Box::leak(Box::new(Self::new()))
26    }
27}
28
29impl log::Log for UefiLogger {
30    fn enabled(&self, metadata: &Metadata) -> bool {
31        metadata.level() <= Level::Info
32    }
33
34    fn log(&self, record: &Record) {
35        if self.enabled(record.metadata()) {
36            let time = runtime::get_time().unwrap_or(runtime::Time::invalid());
37            let level = record.level();
38            let file = record.file().unwrap_or_default();
39            let line = record.line().unwrap_or_default();
40            let args = record.args();
41            with_stdout(|stdout| {
42                let _ = stdout.write_fmt(format_args!("[{time} {level} {file}:{line}] - {args}\n"));
43            });
44        }
45    }
46
47    fn flush(&self) {}
48}