async_logging 0.1.8

An asynchronous logging library for Rust, designed to be simple and efficient.
Documentation
use colored::Colorize;
use once_cell::sync::Lazy;
use std::sync::Arc;
use tokio::sync::{mpsc, Mutex};
struct LogMessage {
    text: String,
    level: Level,
}

/**

 * returns the prefix for the log message based on the log level.
 * This function is used to format the log message with a specific prefix.
 *
 * # Arguments
 * * `level` - The log level of the message.
 */

pub fn get_prefix(level: Level) -> String {
    return match level {
        Level::INFO => "[INFO]:".white().to_string(),
        Level::DEBUG => "[DEBUG]:".bright_cyan().to_string(),
        Level::ERROR => "[ERROR]:".red().to_string(),
        Level::WARNING => "[WARNING]:".yellow().to_string(),
        Level::CRITICAL => "[CRITICAL]:".magenta().to_string(),
    };
}

static LOGGER: Lazy<Arc<Mutex<Option<mpsc::Sender<LogMessage>>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));

/**

 * Initialize the logger with a buffer size.
 * This function spawns a background worker that receives log messages and prints them to the console.
 * The buffer size determines how many messages can be queued before the sender blocks.
 * # Arguments
 * * `buffer_size` - The size of the buffer for the channel.
 */
pub async fn init(buffer_size: usize) {
    let (tx, mut rx) = mpsc::channel::<LogMessage>(buffer_size);

    let mut logger = LOGGER.lock().await;
    *logger = Some(tx);

    // Spawn background worker
    tokio::spawn(async move {
        while let Some(message) = rx.recv().await {
            match message.level {
                Level::INFO => println!("{} {}", get_prefix(message.level), message.text.white()),
                Level::DEBUG => println!(
                    "{}: {}",
                    get_prefix(message.level),
                    message.text.bright_cyan()
                ),
                Level::ERROR => println!("{} {}", get_prefix(message.level), message.text.red()),
                Level::WARNING => {
                    println!("{} {}", get_prefix(message.level), message.text.yellow())
                }
                Level::CRITICAL => {
                    println!("{} {}", get_prefix(message.level), message.text.magenta())
                }
            }
        }
    });
}

/**

 * Shutdown the logger and stop the background worker.
 * This function will drop the sender and close the channel, allowing the background worker to exit.
 * It is important to call this function before the program exits to ensure that all log messages are flushed.
 */
pub async fn shutdown() {
    let mut logger = LOGGER.lock().await;
    *logger = None;
}

/**

 * Log a message with a specific log level.
 * This function sends the log message to the background worker for processing.
 * If the logger is not initialized, it will print the message directly to the console.
 * # Arguments
 * * `text` - The log message to be logged.
 * * `level` - The log level of the message.
 */
pub async fn log(text: &str, level: Level) {
    if let Some(sender) = &*LOGGER.lock().await {
        let _ = sender
            .send(LogMessage {
                text: text.to_owned(),
                level,
            })
            .await;
    } else {
        let final_text = match level {
            Level::INFO => text.white(),
            Level::DEBUG => text.blue(),
            Level::ERROR => text.red(),
            Level::WARNING => text.yellow(),
            Level::CRITICAL => text.magenta(),
        };
        println!("{}: {}", get_prefix(level), final_text);
    }
}

#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => {
        $crate::log(&format!($($arg)*), $crate::Level::DEBUG).await
    };
}

#[macro_export]
macro_rules! info {
    ($($arg:tt)*) => {
        $crate::log(&format!($($arg)*), $crate::Level::INFO).await
    };
}

#[macro_export]
macro_rules! error {
    ($($arg:tt)*) => {
        $crate::log(&format!($($arg)*), $crate::Level::ERROR).await
    };
}

#[macro_export]
macro_rules! warning {
    ($($arg:tt)*) => {
        $crate::log(&format!($($arg)*), $crate::Level::WARNING).await
    };
}

#[macro_export]
macro_rules! critical {
    ($($arg:tt)*) => {
        $crate::log(&format!($($arg)*), $crate::Level::CRITICAL).await
    };
}

#[derive(Debug, Clone, Copy)]
pub enum Level {
    INFO,
    ERROR,
    DEBUG,
    WARNING,
    CRITICAL,
}