use std::io::{IsTerminal, stdin};
use colored::{ColoredString, Colorize};
use logforth::record::Level;
use crate::Kv;
#[derive(Debug)]
pub struct Text {
pub color: bool,
}
pub fn level_color(level: Level) -> ColoredString {
match level {
Level::Error => level.to_string().red(),
Level::Warn => level.to_string().yellow(),
Level::Info => level.to_string().green(),
Level::Debug => level.to_string().blue(),
Level::Trace => level.to_string().magenta(),
_ => level.to_string().into(),
}
}
impl Default for Text {
fn default() -> Self {
Self {
color: stdin().is_terminal(),
}
}
}
impl logforth::Layout for Text {
fn format(
&self,
record: &logforth::record::Record<'_>,
diagnostics: &[Box<dyn logforth::diagnostic::Diagnostic>],
) -> Result<Vec<u8>, logforth::Error> {
let level = record.level();
let file = if let Some(file) = record.file() {
if crate::ROOT.len() > 1
&& let Some(f) = file.strip_prefix(crate::ROOT.as_str())
{
f.into()
} else if let Some(f) = file.strip_prefix(crate::HOME_DIR.as_str()) {
format!("~/{f}")
} else {
file.into()
}
} else {
record.target().into()
};
let file_line = if let Some(line) = record.line() {
format!("{file}:{line}")
} else {
file
};
let msg = record.payload();
let mut visitor = Kv {
text: String::new(),
};
record.key_values().visit(&mut visitor)?;
for d in diagnostics {
d.visit(&mut visitor)?;
}
let msg = if visitor.text.is_empty() {
msg.to_string()
} else {
format!("{} {}", msg, visitor.text)
};
let msg = if self.color {
let level = level_color(level);
let file_line = file_line.bright_black();
format!("{level} {file_line} {msg}")
} else {
let ts = coarsetime::Clock::now_since_epoch().as_secs();
let ts = {
if let Ok(timestamp) = jiff::Timestamp::from_second(ts as i64) {
jiff::Zoned::new(timestamp, crate::TZ.clone())
.strftime("%Y-%m-%d %H:%M:%S")
.to_string()
} else {
ts.to_string()
}
};
format!("{level} {ts} {file_line} {msg}")
};
Ok(msg.as_bytes().into())
}
}