blob: c30adad96b0bac0633c7398478f7dd9b56b4a689 [file] [log] [blame]
David Brazdil8b557772022-07-05 12:22:20 +01001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Logger for vmbase.
16//!
17//! Internally uses the println! vmbase macro, which prints to crosvm's UART.
18//! Note: may not work if the VM is in an inconsistent state. Exception handlers
19//! should avoid using this logger and instead print with eprintln!.
20
Jakob Vukalovicef996292023-04-13 14:28:34 +000021use crate::console::println;
22use core::sync::atomic::{AtomicBool, Ordering};
David Brazdil8b557772022-07-05 12:22:20 +010023use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
24
Jakob Vukalovicef996292023-04-13 14:28:34 +000025struct Logger {
26 is_enabled: AtomicBool,
27}
28static mut LOGGER: Logger = Logger::new();
29
30impl Logger {
31 const fn new() -> Self {
32 Self { is_enabled: AtomicBool::new(true) }
33 }
34
35 fn swap_enabled(&mut self, enabled: bool) -> bool {
36 self.is_enabled.swap(enabled, Ordering::Relaxed)
37 }
38}
David Brazdil8b557772022-07-05 12:22:20 +010039
40impl Log for Logger {
41 fn enabled(&self, _metadata: &Metadata) -> bool {
Jakob Vukalovicef996292023-04-13 14:28:34 +000042 self.is_enabled.load(Ordering::Relaxed)
David Brazdil8b557772022-07-05 12:22:20 +010043 }
44
45 fn log(&self, record: &Record) {
Jakob Vukalovicef996292023-04-13 14:28:34 +000046 if self.enabled(record.metadata()) {
47 println!("[{}] {}", record.level(), record.args());
48 }
David Brazdil8b557772022-07-05 12:22:20 +010049 }
50
51 fn flush(&self) {}
52}
53
Jakob Vukalovicef996292023-04-13 14:28:34 +000054/// An RAII implementation of a log suppressor. When the instance is dropped, logging is re-enabled.
55pub struct SuppressGuard {
56 old_enabled: bool,
57}
58
59impl SuppressGuard {
60 fn new() -> Self {
61 // Safe because it modifies an atomic.
62 unsafe { Self { old_enabled: LOGGER.swap_enabled(false) } }
63 }
64}
65
66impl Drop for SuppressGuard {
67 fn drop(&mut self) {
68 // Safe because it modifies an atomic.
69 unsafe {
70 LOGGER.swap_enabled(self.old_enabled);
71 }
72 }
73}
74
David Brazdil8b557772022-07-05 12:22:20 +010075/// Initialize vmbase logger with a given max logging level.
76pub fn init(max_level: LevelFilter) -> Result<(), SetLoggerError> {
Jakob Vukalovicef996292023-04-13 14:28:34 +000077 // Safe because it only sets the global logger.
78 unsafe {
79 log::set_logger(&LOGGER)?;
80 }
David Brazdil8b557772022-07-05 12:22:20 +010081 log::set_max_level(max_level);
82 Ok(())
83}
Jakob Vukalovicef996292023-04-13 14:28:34 +000084
85/// Suppress logging until the return value goes out of scope.
86pub fn suppress() -> SuppressGuard {
87 SuppressGuard::new()
88}