blob: 94dc88084d7d1c92f576e361938d245e2fd92495 [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
21extern crate log;
22
Jakob Vukalovicef996292023-04-13 14:28:34 +000023use crate::console::println;
24use core::sync::atomic::{AtomicBool, Ordering};
David Brazdil8b557772022-07-05 12:22:20 +010025use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
26
Jakob Vukalovicef996292023-04-13 14:28:34 +000027struct Logger {
28 is_enabled: AtomicBool,
29}
30static mut LOGGER: Logger = Logger::new();
31
32impl Logger {
33 const fn new() -> Self {
34 Self { is_enabled: AtomicBool::new(true) }
35 }
36
37 fn swap_enabled(&mut self, enabled: bool) -> bool {
38 self.is_enabled.swap(enabled, Ordering::Relaxed)
39 }
40}
David Brazdil8b557772022-07-05 12:22:20 +010041
42impl Log for Logger {
43 fn enabled(&self, _metadata: &Metadata) -> bool {
Jakob Vukalovicef996292023-04-13 14:28:34 +000044 self.is_enabled.load(Ordering::Relaxed)
David Brazdil8b557772022-07-05 12:22:20 +010045 }
46
47 fn log(&self, record: &Record) {
Jakob Vukalovicef996292023-04-13 14:28:34 +000048 if self.enabled(record.metadata()) {
49 println!("[{}] {}", record.level(), record.args());
50 }
David Brazdil8b557772022-07-05 12:22:20 +010051 }
52
53 fn flush(&self) {}
54}
55
Jakob Vukalovicef996292023-04-13 14:28:34 +000056/// An RAII implementation of a log suppressor. When the instance is dropped, logging is re-enabled.
57pub struct SuppressGuard {
58 old_enabled: bool,
59}
60
61impl SuppressGuard {
62 fn new() -> Self {
63 // Safe because it modifies an atomic.
64 unsafe { Self { old_enabled: LOGGER.swap_enabled(false) } }
65 }
66}
67
68impl Drop for SuppressGuard {
69 fn drop(&mut self) {
70 // Safe because it modifies an atomic.
71 unsafe {
72 LOGGER.swap_enabled(self.old_enabled);
73 }
74 }
75}
76
David Brazdil8b557772022-07-05 12:22:20 +010077/// Initialize vmbase logger with a given max logging level.
78pub fn init(max_level: LevelFilter) -> Result<(), SetLoggerError> {
Jakob Vukalovicef996292023-04-13 14:28:34 +000079 // Safe because it only sets the global logger.
80 unsafe {
81 log::set_logger(&LOGGER)?;
82 }
David Brazdil8b557772022-07-05 12:22:20 +010083 log::set_max_level(max_level);
84 Ok(())
85}
Jakob Vukalovicef996292023-04-13 14:28:34 +000086
87/// Suppress logging until the return value goes out of scope.
88pub fn suppress() -> SuppressGuard {
89 SuppressGuard::new()
90}