1use log::{Level, LevelFilter};
2
3use crate::hostcalls::{self, LogLevel};
4use std::borrow::Cow;
5use std::panic;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8struct Logger;
9
10static LOGGER: Logger = Logger;
11static INITIALIZED: AtomicBool = AtomicBool::new(false);
12
13impl From<Level> for LogLevel {
14 fn from(val: Level) -> Self {
15 match val {
16 Level::Error => LogLevel::Error,
17 Level::Warn => LogLevel::Warn,
18 Level::Info => LogLevel::Info,
19 Level::Debug => LogLevel::Debug,
20 Level::Trace => LogLevel::Trace,
21 }
22 }
23}
24
25impl From<LogLevel> for LevelFilter {
26 fn from(val: LogLevel) -> Self {
27 match val {
28 LogLevel::Trace => LevelFilter::Trace,
29 LogLevel::Debug => LevelFilter::Debug,
30 LogLevel::Info => LevelFilter::Info,
31 LogLevel::Warn => LevelFilter::Warn,
32 LogLevel::Error => LevelFilter::Error,
33 LogLevel::Critical => LevelFilter::Off,
34 }
35 }
36}
37
38pub fn set_log_level(level: Level) {
40 if !INITIALIZED.load(Ordering::Relaxed) {
41 log::set_logger(&LOGGER).unwrap();
42 panic::set_hook(Box::new(|panic_info| {
43 hostcalls::log(LogLevel::Critical, &panic_info.to_string()).unwrap();
44 }));
45 INITIALIZED.store(true, Ordering::Relaxed);
46 }
47 LOGGER.set_log_level(level.into());
48}
49
50impl Logger {
51 pub fn set_log_level(&self, level: LogLevel) {
52 log::set_max_level(level.into());
53 }
54}
55
56impl log::Log for Logger {
57 fn enabled(&self, metadata: &log::Metadata) -> bool {
58 metadata.level() <= log::max_level()
59 }
60
61 fn log(&self, record: &log::Record) {
62 if self.enabled(record.metadata()) {
63 let args = record.args();
64 let message = match args.as_str() {
65 Some(v) => Cow::Borrowed(v),
66 None => Cow::Owned(args.to_string()),
67 };
68 hostcalls::log(record.level().into(), &message).unwrap();
69 }
70 }
71
72 fn flush(&self) {}
73}