A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
2.8 KiB

use std::cell::RefCell;
use std::cmp::min;
use std::io::{stderr, Write};
use std::rc::Rc;
// The log crate defines
// 1 - Error, 2 - Warn, 3 - Info, 4 - Debug, 5 - Trace
pub type Level = usize;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Entry<S>(pub Level, pub S);
pub trait Logger {
fn write(&self, level: Level, msg: &str);
fn writeln(&self, level: Level, msg: &str);
fn info(&self, msg: &str) {
self.writeln(3, msg);
}
fn debug(&self, msg: &str) {
self.writeln(4, msg);
}
fn trace(&self, msg: &str) {
self.writeln(5, msg);
}
fn put<'a>(&self, entries: impl IntoIterator<Item = Entry<&'a str>>) -> usize {
let mut c = 0;
for item in entries {
self.writeln(item.0, item.1);
c += 1;
}
c
}
}
#[derive(Debug, Default)]
pub struct StdErrLogger {
line_started: RefCell<bool>,
}
impl Logger for StdErrLogger {
fn write(&self, _level: Level, msg: &str) {
*self.line_started.borrow_mut() = true;
write!(&mut stderr(), "{msg}").expect("Could not write to stderr");
}
fn writeln(&self, _level: Level, msg: &str) {
if self.line_started.replace(false) {
writeln!(&mut stderr()).expect("Could not write to stderr");
}
writeln!(&mut stderr(), "{msg}").expect("Could not write to stderr");
}
}
impl Drop for StdErrLogger {
fn drop(&mut self) {
if *self.line_started.borrow() {
writeln!(&mut stderr()).expect("Could not write to stderr");
}
}
}
#[derive(Debug)]
pub struct FilteringLogger<'a, L> {
logger: &'a L,
max_level: Level,
}
impl<'a, L> FilteringLogger<'a, L> {
pub const fn new(logger: &'a L, max_level: Level) -> Self {
Self { logger, max_level }
}
}
impl<'a, L: Logger> Logger for FilteringLogger<'a, L> {
fn write(&self, level: Level, msg: &str) {
if level <= self.max_level {
self.logger.write(level, msg);
}
}
fn writeln(&self, level: Level, msg: &str) {
if level <= self.max_level {
self.logger.writeln(level, msg);
}
}
}
#[derive(Clone, Debug, Default)]
pub struct StoringLogger {
log: Rc<RefCell<(bool, Vec<Entry<String>>)>>,
}
impl StoringLogger {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn release(self) -> Vec<Entry<String>> {
Rc::try_unwrap(self.log).unwrap().into_inner().1
}
}
impl Logger for StoringLogger {
fn write(&self, level: Level, msg: &str) {
let mut log = self.log.borrow_mut();
let entry = if log.0 {
log.1.pop().map(|e| Entry(min(e.0, level), e.1 + msg))
} else {
None
}
.unwrap_or_else(|| Entry(level, msg.to_string()));
log.0 = true;
log.1.push(entry);
}
fn writeln(&self, level: Level, msg: &str) {
let mut log = self.log.borrow_mut();
log.0 = false;
log.1.push(Entry(level, msg.to_string()));
}
}
#[cfg(test)]
mod test {}