1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
//! Logging utilities.
use lazy_static::lazy_static;
use std::collections::VecDeque;
use std::sync::Mutex;
/// Saves all log records in a global deque.
///
/// Uses a `DebugView` to access it.
pub struct CursiveLogger;
static LOGGER: CursiveLogger = CursiveLogger;
/// A log record.
pub struct Record {
/// Log level used for this record
pub level: log::Level,
/// Time this message was logged
pub time: time::OffsetDateTime,
/// Message content
pub message: String,
}
lazy_static! {
/// Circular buffer for logs. Use it to implement [`DebugView`].
///
/// [`DebugView`]: ../views/struct.DebugView.html
pub static ref LOGS: Mutex<VecDeque<Record>> =
Mutex::new(VecDeque::new());
}
/// Log a record in cursive's log queue.
pub fn log(record: &log::Record<'_>) {
let mut logs = LOGS.lock().unwrap();
// TODO: customize the format? Use colors? Save more info?
if logs.len() == logs.capacity() {
logs.pop_front();
}
logs.push_back(Record {
level: record.level(),
message: format!("{}", record.args()),
time: time::OffsetDateTime::now_local()
.unwrap_or_else(|_| time::OffsetDateTime::now_utc()),
});
}
impl log::Log for CursiveLogger {
fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
true
}
fn log(&self, record: &log::Record<'_>) {
log(record);
}
fn flush(&self) {}
}
/// Initialize the Cursive logger.
///
/// Make sure this is the only logger your are using.
///
/// Use a [`DebugView`](crate::views::DebugView) to see the logs, or use
/// [`Cursive::toggle_debug_console()`](crate::Cursive::toggle_debug_console()).
pub fn init() {
// TODO: Configure the deque size?
reserve_logs(1_000);
// This will panic if `set_logger` was already called.
log::set_logger(&LOGGER).unwrap();
// TODO: read the level from env variable? From argument?
log::set_max_level(log::LevelFilter::Trace);
}
/// Return a logger that stores records in cursive's log queue.
///
/// These logs can then be read by a [`DebugView`](crate::views::DebugView).
///
/// An easier alternative might be to use [`init()`].
pub fn get_logger() -> CursiveLogger {
reserve_logs(1_000);
CursiveLogger
}
/// Adds `n` more entries to cursive's log queue.
///
/// Most of the time you don't need to use this directly.
///
/// You should call this if you're not using `init()` nor `get_logger()`.
pub fn reserve_logs(n: usize) {
LOGS.lock().unwrap().reserve(n);
}