feat(logger): ✨ console logger
This commit is contained in:
parent
ff3901c64e
commit
6871646072
158
Cargo.lock
generated
158
Cargo.lock
generated
@ -2,12 +2,41 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtt"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6b2dd9ee2d76888dc4c17d6da74629fa11b3cb1e8094fdc159b7f8ff259fc88"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
@ -24,16 +53,145 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "lool"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"dtt",
|
||||
"eyre",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
@ -30,4 +30,6 @@ cli-stylize = ["dep:bitflags"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = { version = "2.5.0", optional = true}
|
||||
dtt = "0.0.5"
|
||||
eyre = { version = "0.6.12", default-features = false }
|
||||
log = "0.4.21"
|
||||
|
||||
12
examples/logger.rs
Normal file
12
examples/logger.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use log::Level;
|
||||
use lool::logger::ConsoleLogger;
|
||||
|
||||
|
||||
fn main() {
|
||||
ConsoleLogger::default_setup(Level::Trace, "test").unwrap();
|
||||
log::info!("log line");
|
||||
log::warn!("log line");
|
||||
log::error!("log line");
|
||||
log::debug!("log line");
|
||||
log::trace!("log line");
|
||||
}
|
||||
@ -17,6 +17,7 @@ fn main() -> Result<()> {
|
||||
let red_on_blue = stylize("[white on blue]", "white on blue");
|
||||
let rgb = stylize("[#3a95ef]", "#3a95ef");
|
||||
let rgb_on_rgb = stylize("[#3a95ef on #c174dd]", "#3a95ef on #c174dd");
|
||||
let rgb_dim = stylize("[#3a95ef+dimmed]", "#3a95ef+dimmed");
|
||||
|
||||
println!("pre {} post", red_bold);
|
||||
println!("pre {} post", alt_red_bold);
|
||||
@ -26,6 +27,7 @@ fn main() -> Result<()> {
|
||||
println!("pre {} post", red_on_blue);
|
||||
println!("pre {} post", rgb);
|
||||
println!("pre {} post", rgb_on_rgb);
|
||||
println!("pre {} post", rgb_dim);
|
||||
|
||||
println!("pre {} post", "[green]".stl("green").stl("+bold"));
|
||||
println!("pre {} post", "[green+bold]".stl("green+bold"));
|
||||
@ -34,5 +36,8 @@ fn main() -> Result<()> {
|
||||
println!("pre {} post", "[.blue().bold()]".blue().bold());
|
||||
println!("pre {} post", "[.blue().on_red().bold()]".blue().on_red().bold());
|
||||
|
||||
println!("pre {} post", "[.dim()]".dim());
|
||||
println!("pre {} post", "[.blue().dim()]".blue().dim());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -126,7 +126,7 @@ pub trait Stylize {
|
||||
fn on_bright_white(&self) -> String { self.stl("on bright-white") }
|
||||
fn on_rgb(&self, r: u8, g: u8, b: u8) -> String { self.stl(&format!("on #{:02X}{:02X}{:02X}", r, g, b)) }
|
||||
fn bold(&self) -> String { self.stl("+bold") }
|
||||
fn dim(&self) -> String { self.stl("+dim") }
|
||||
fn dim(&self) -> String { self.stl("+dimmed") }
|
||||
fn italic(&self) -> String { self.stl("+italic") }
|
||||
fn underline(&self) -> String { self.stl("+underline") }
|
||||
fn blink(&self) -> String { self.stl("+blink") }
|
||||
|
||||
@ -1 +1,2 @@
|
||||
pub mod cli;
|
||||
pub mod cli;
|
||||
pub mod logger;
|
||||
60
lib/logger/datetime.rs
Normal file
60
lib/logger/datetime.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub fn noop_datetime() -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
/// Get the current time in the format yyyy-mm-dd hh:mm:ss
|
||||
pub fn utc_current_time() -> String {
|
||||
// Get the current system time
|
||||
let now = SystemTime::now();
|
||||
|
||||
// Convert the adjusted time to a formatted string
|
||||
match now.duration_since(UNIX_EPOCH) {
|
||||
Ok(duration) => {
|
||||
let secs = duration.as_secs();
|
||||
let days = secs / (24 * 3600);
|
||||
let mut years = 1970;
|
||||
let mut days_left = days;
|
||||
|
||||
// Adjusting for leap years
|
||||
loop {
|
||||
let days_in_year = if is_leap_year(years) { 366 } else { 365 };
|
||||
if days_left < days_in_year {
|
||||
break;
|
||||
}
|
||||
days_left -= days_in_year;
|
||||
years += 1;
|
||||
}
|
||||
|
||||
let (month, day) = days_to_date(days_left, is_leap_year(years));
|
||||
|
||||
let hours = (secs / 3600) % 24;
|
||||
let minutes = (secs / 60) % 60;
|
||||
let seconds = secs % 60;
|
||||
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", years, month + 1, day, hours, minutes, seconds)
|
||||
}
|
||||
Err(_) => "0".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a year is a leap year
|
||||
fn is_leap_year(year: u64) -> bool {
|
||||
(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
|
||||
}
|
||||
|
||||
// Calculate the month and day from the number of days since UNIX epoch
|
||||
fn days_to_date(days: u64, leap: bool) -> (u64, u64) {
|
||||
let days_in_month = [31, if leap { 29 } else { 28 }, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let mut days_left = days;
|
||||
let mut month = 0;
|
||||
|
||||
while days_left >= days_in_month[month as usize] {
|
||||
days_left -= days_in_month[month as usize];
|
||||
month += 1;
|
||||
}
|
||||
|
||||
(month, days_left + 1) // Adding 1 to day to make it 1-based
|
||||
}
|
||||
|
||||
97
lib/logger/mod.rs
Normal file
97
lib/logger/mod.rs
Normal file
@ -0,0 +1,97 @@
|
||||
pub mod datetime;
|
||||
|
||||
use eyre::{eyre, Result};
|
||||
use log::{Level, Metadata, Record};
|
||||
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
struct StyledRecord {
|
||||
time: String,
|
||||
level: String,
|
||||
message: String,
|
||||
file: String,
|
||||
line: String,
|
||||
}
|
||||
|
||||
impl StyledRecord {
|
||||
fn from(record: &Record, get_time: fn() -> String) -> Self {
|
||||
let ansi_style_level = match record.level() {
|
||||
Level::Error => "\x1b[31m", // red
|
||||
Level::Warn => "\x1b[33m", // yellow
|
||||
Level::Info => "\x1b[32m", // green
|
||||
Level::Debug => "\x1b[95m", // magenta
|
||||
Level::Trace => "\x1b[34m", // blue
|
||||
};
|
||||
|
||||
let file_ansi_color = "\x1b[34m"; // blue
|
||||
let line_ansi_color = "\x1b[34;1m"; // bold blue
|
||||
let mut time = get_time();
|
||||
|
||||
if !time.is_empty() {
|
||||
time = format!("\x1b[2m{}\x1b[0m", time); // dim
|
||||
}
|
||||
|
||||
Self {
|
||||
level: format!("{}{:<5}{}", ansi_style_level, record.level(), RESET),
|
||||
message: format!("{}", record.args()),
|
||||
file: format!("{}{}{}", file_ansi_color, record.file().unwrap_or("unknown"), RESET),
|
||||
line: format!("{}{}{}", line_ansi_color, record.line().unwrap_or(0), RESET),
|
||||
time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConsoleLogger<'a>{
|
||||
context: &'a str,
|
||||
time_fn: fn() -> String,
|
||||
}
|
||||
|
||||
impl<'a> ConsoleLogger<'a> {
|
||||
pub fn default_setup(max_level: Level, context: &'static str) -> Result<()> {
|
||||
let logger = Box::new(ConsoleLogger { context, time_fn: datetime::utc_current_time});
|
||||
log::set_logger(Box::leak(logger) as &'static ConsoleLogger)
|
||||
.map(|()| log::set_max_level(max_level.to_level_filter()))
|
||||
.map_err(|err| eyre!("failed to set logger: {}", err))
|
||||
}
|
||||
|
||||
pub fn setup(max_level: Level, context: &'static str, time_fn: fn() -> String) -> Result<()> {
|
||||
let logger = Box::new(ConsoleLogger { context, time_fn});
|
||||
log::set_logger(Box::leak(logger) as &'static ConsoleLogger)
|
||||
.map(|()| log::set_max_level(max_level.to_level_filter()))
|
||||
.map_err(|err| eyre!("failed to set logger: {}", err))
|
||||
}
|
||||
|
||||
pub fn set_context(&mut self, context: &'a str) {
|
||||
self.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
/// simple implementation of a themed logger
|
||||
impl<'a> log::Log for ConsoleLogger<'a> {
|
||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
metadata.level() <= Level::Info
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
let styled_record = StyledRecord::from(record, self.time_fn);
|
||||
|
||||
let time = if styled_record.time.is_empty() {
|
||||
" ".to_string()
|
||||
} else {
|
||||
format!(" {} ", styled_record.time)
|
||||
};
|
||||
|
||||
// print to stdout
|
||||
println!(
|
||||
"[{}]{}| {} | {}:{} - {}",
|
||||
self.context,
|
||||
time,
|
||||
styled_record.level,
|
||||
styled_record.file,
|
||||
styled_record.line,
|
||||
styled_record.message
|
||||
);
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user