Files
payphone/src/logging.rs
T
2025-08-12 22:45:59 -03:00

93 lines
2.7 KiB
Rust

//! Log handling and formatting of the console's output.
//!
//! # Logging
//!
//! Payphone uses the [`log`] crate for logging, and the [`colored`] crate for formatting the
//! output.
//!
//! Any logs that are not coming from the `payphone` crate are ignored.
//!
//! ## Logging Levels
//!
//! There are 5 different logging levels:
//!
//! - `trace`: The most verbose level, used for debugging purposes.
//! - `debug`: Events that are useful to be displayed during development, but not in production.
//! - `info`: Used for general information about the bot's state and milestones.
//! - `warn`: Used for warnings, when something unexpected happens but the bot can still continue
//! running.
//! - `error`: Used for errors, when something goes wrong and the bot cannot continue running.
//!
//! ## Usage
//!
//! Logging is quite simple as it works like any [`println!`] calls.
//!
//! ```
//! log::trace!("This is a trace message.");
//! log::debug!("This is a debug message.");
//! log::info!("This is an info message.");
//! log::warn!("This is a warning message.");
//! log::error!("This is an error message.");
//! ```
//!
//! Logging supports formatting, so you can use it like any other [`println!`] call:
//!
//! ```
//! let value = 42;
//! log::info!("The value is: {value}");
//! ```
use colored::Colorize;
use log::{Level, LevelFilter};
use time::{OffsetDateTime, macros::format_description};
pub struct Logger;
impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.target() == "payphone" || metadata.target().starts_with("payphone::")
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
println!(
"{} {} {}",
get_formatted_timestamp(),
get_formatted_level(record.level()),
record.args(),
);
}
}
fn flush(&self) {}
}
pub fn init(level: LevelFilter) {
log::set_logger(&Logger)
.map(|()| log::set_max_level(level))
.unwrap();
}
fn get_formatted_timestamp() -> String {
let now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
let format = format_description!(
"[day]/[month]/[year] at [hour]:[minute]:[second].[subsecond digits:2]"
);
now.format(&format).unwrap().dimmed().to_string()
}
fn get_formatted_level(level: Level) -> String {
let string = format!("[{level}]");
let string = format!("{string:<7}");
match level {
Level::Trace => string.dimmed().to_string(),
Level::Debug => string.white().to_string(),
Level::Info => string.blue().to_string(),
Level::Warn => string.yellow().to_string(),
Level::Error => string.red().bold().to_string(),
}
}