Skip to main content

wrkflw_logging/
lib.rs

1use chrono::Local;
2use once_cell::sync::Lazy;
3use std::sync::{Arc, Mutex};
4
5// Thread-safe log storage
6static LOGS: Lazy<Arc<Mutex<Vec<String>>>> = Lazy::new(|| Arc::new(Mutex::new(Vec::new())));
7
8// Current log level
9static LOG_LEVEL: Lazy<Arc<Mutex<LogLevel>>> = Lazy::new(|| Arc::new(Mutex::new(LogLevel::Info)));
10
11// Log levels
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13pub enum LogLevel {
14    Debug,
15    Info,
16    Warning,
17    Error,
18}
19
20impl LogLevel {
21    fn prefix(&self) -> &'static str {
22        match self {
23            LogLevel::Debug => "🔍",
24            LogLevel::Info => "â„šī¸",
25            LogLevel::Warning => "âš ī¸",
26            LogLevel::Error => "❌",
27        }
28    }
29}
30
31// Set the current log level
32pub fn set_log_level(level: LogLevel) {
33    if let Ok(mut current_level) = LOG_LEVEL.lock() {
34        *current_level = level;
35    }
36}
37
38// Get the current log level
39pub fn get_log_level() -> LogLevel {
40    if let Ok(level) = LOG_LEVEL.lock() {
41        *level
42    } else {
43        // Default to Info if we can't get the lock
44        LogLevel::Info
45    }
46}
47
48// Log a message with timestamp and level
49pub fn log(level: LogLevel, message: &str) {
50    let timestamp = Local::now().format("%H:%M:%S").to_string();
51
52    // Always include timestamp in [HH:MM:SS] format to ensure consistency
53    let formatted = format!("[{}] {} {}", timestamp, level.prefix(), message);
54
55    if let Ok(mut logs) = LOGS.lock() {
56        logs.push(formatted.clone());
57    }
58
59    // Print to console if the message level is >= the current log level
60    // This ensures Debug messages only show up when the Debug level is set
61    if let Ok(current_level) = LOG_LEVEL.lock() {
62        if level >= *current_level {
63            // Print to stdout/stderr based on level
64            match level {
65                LogLevel::Error | LogLevel::Warning => eprintln!("{}", formatted),
66                _ => println!("{}", formatted),
67            }
68        }
69    }
70}
71
72// Get all logs
73pub fn get_logs() -> Vec<String> {
74    if let Ok(logs) = LOGS.lock() {
75        logs.clone()
76    } else {
77        // If we can't access logs, return an error message with timestamp
78        let timestamp = Local::now().format("%H:%M:%S").to_string();
79        vec![format!("[{}] ❌ Error accessing logs", timestamp)]
80    }
81}
82
83// Clear all logs
84#[allow(dead_code)]
85pub fn clear_logs() {
86    if let Ok(mut logs) = LOGS.lock() {
87        logs.clear();
88    }
89}
90
91// Convenience functions for different log levels
92#[allow(dead_code)]
93pub fn debug(message: &str) {
94    log(LogLevel::Debug, message);
95}
96
97pub fn info(message: &str) {
98    log(LogLevel::Info, message);
99}
100
101pub fn warning(message: &str) {
102    log(LogLevel::Warning, message);
103}
104
105pub fn error(message: &str) {
106    log(LogLevel::Error, message);
107}