//! 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(), } }