blob: 226d9051e2947321d8880dfdb579032537aee3ec [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}
Andrew Walbranc568ae02023-07-05 13:53:02 +000028
29static LOGGER: Logger = Logger::new();
Jakob Vukalovicef996292023-04-13 14:28:34 +000030
31impl Logger {
32 const fn new() -> Self {
33 Self { is_enabled: AtomicBool::new(true) }
34 }
35
Andrew Walbranc568ae02023-07-05 13:53:02 +000036 fn swap_enabled(&self, enabled: bool) -> bool {
Jakob Vukalovicef996292023-04-13 14:28:34 +000037 self.is_enabled.swap(enabled, Ordering::Relaxed)
38 }
39}
David Brazdil8b557772022-07-05 12:22:20 +010040
41impl Log for Logger {
42 fn enabled(&self, _metadata: &Metadata) -> bool {
Jakob Vukalovicef996292023-04-13 14:28:34 +000043 self.is_enabled.load(Ordering::Relaxed)
David Brazdil8b557772022-07-05 12:22:20 +010044 }
45
46 fn log(&self, record: &Record) {
Jakob Vukalovicef996292023-04-13 14:28:34 +000047 if self.enabled(record.metadata()) {
48 println!("[{}] {}", record.level(), record.args());
49 }
David Brazdil8b557772022-07-05 12:22:20 +010050 }
51
52 fn flush(&self) {}
53}
54
Jakob Vukalovicef996292023-04-13 14:28:34 +000055/// An RAII implementation of a log suppressor. When the instance is dropped, logging is re-enabled.
56pub struct SuppressGuard {
57 old_enabled: bool,
58}
59
60impl SuppressGuard {
61 fn new() -> Self {
Andrew Walbranc568ae02023-07-05 13:53:02 +000062 Self { old_enabled: LOGGER.swap_enabled(false) }
Jakob Vukalovicef996292023-04-13 14:28:34 +000063 }
64}
65
66impl Drop for SuppressGuard {
67 fn drop(&mut self) {
Andrew Walbranc568ae02023-07-05 13:53:02 +000068 LOGGER.swap_enabled(self.old_enabled);
Jakob Vukalovicef996292023-04-13 14:28:34 +000069 }
70}
71
David Brazdil8b557772022-07-05 12:22:20 +010072/// Initialize vmbase logger with a given max logging level.
73pub fn init(max_level: LevelFilter) -> Result<(), SetLoggerError> {
Andrew Walbranc568ae02023-07-05 13:53:02 +000074 log::set_logger(&LOGGER)?;
David Brazdil8b557772022-07-05 12:22:20 +010075 log::set_max_level(max_level);
76 Ok(())
77}
Jakob Vukalovicef996292023-04-13 14:28:34 +000078
79/// Suppress logging until the return value goes out of scope.
80pub fn suppress() -> SuppressGuard {
81 SuppressGuard::new()
82}