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.

131 lines
3.0 KiB

use std::cell::RefCell;
use std::cmp::min;
use std::io::stderr;
use std::io::Write;
// The log crate defines
// 1 - Error, 2 - Warn, 3 - Info, 4 - Debug, 5 - Trace
pub type Level = usize;
#[derive(Debug)]
pub struct Entry<S>(pub Level, pub S);
pub trait Logger {
fn write<S: AsRef<str> + Into<String>>(&self, level: Level, msg: S)
where
Self: Sized;
fn writeln<S: AsRef<str> + Into<String>>(&self, level: Level, msg: S)
where
Self: Sized;
fn info<S: AsRef<str> + Into<String>>(&self, msg: S)
where
Self: Sized,
{
self.writeln(3, msg)
}
fn debug<S: AsRef<str> + Into<String>>(&self, msg: S)
where
Self: Sized,
{
self.writeln(4, msg)
}
fn trace<S: AsRef<str> + Into<String>>(&self, msg: S)
where
Self: Sized,
{
self.writeln(5, msg)
}
fn put<S: AsRef<str> + Into<String>>(&self, entries: impl IntoIterator<Item = Entry<S>>) -> usize
where
Self: Sized,
{
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<S: AsRef<str> + Into<String>>(&self, _level: Level, msg: S) {
*self.line_started.borrow_mut() = true;
write!(&mut stderr(), "{}", msg.as_ref()).unwrap();
}
fn writeln<S: AsRef<str> + Into<String>>(&self, _level: Level, msg: S) {
if self.line_started.replace(false) {
writeln!(&mut stderr()).unwrap();
}
writeln!(&mut stderr(), "{}", msg.as_ref()).unwrap();
}
}
impl Drop for StdErrLogger {
fn drop(&mut self) {
if *self.line_started.borrow() == true {
writeln!(&mut stderr()).unwrap();
}
}
}
#[derive(Debug)]
pub struct FilteringLogger<'a, L> {
logger: &'a L,
max_level: Level,
}
impl<'a, L> FilteringLogger<'a, L> {
pub fn new(logger: &'a L, max_level: Level) -> Self {
Self { logger, max_level }
}
}
impl<'a, L: Logger> Logger for FilteringLogger<'a, L> {
fn write<S: AsRef<str> + Into<String>>(&self, level: Level, str: S) {
if level <= self.max_level {
self.logger.write(level, str)
}
}
fn writeln<S: AsRef<str> + Into<String>>(&self, level: Level, str: S) {
if level <= self.max_level {
self.logger.writeln(level, str)
}
}
}
#[derive(Debug, Default)]
pub struct StoringLogger {
log: RefCell<Vec<Entry<String>>>,
}
impl StoringLogger {
pub fn new() -> Self {
Self::default()
}
pub fn release(self) -> Vec<Entry<String>> {
self.log.into_inner()
}
}
impl Logger for StoringLogger {
fn write<S: AsRef<str> + Into<String>>(&self, level: Level, line: S) {
let mut log = self.log.borrow_mut();
let entry = log
.pop()
.map(|e| Entry(min(e.0, level), e.1 + line.as_ref()))
.unwrap_or_else(|| Entry(level, line.into()));
log.push(entry);
}
fn writeln<S: AsRef<str> + Into<String>>(&self, level: Level, line: S) {
self.log.borrow_mut().push(Entry(level, line.into()));
}
}
#[cfg(test)]
mod test {}