Skip to main content

cirious_codex_logger/
log.rs

1use crate::{Dispatcher, Level};
2use std::{
3  collections::BTreeMap,
4  error::Error,
5  sync::{atomic::AtomicU8, OnceLock, RwLock},
6};
7
8/// Global log level filter, initialized to `Level::Info` (3).
9pub static GLOBAL_FILTER: AtomicU8 = AtomicU8::new(Level::Info as u8);
10
11/// A registry of module-specific filters.
12pub static MODULE_FILTERS: RwLock<BTreeMap<String, Level>> = RwLock::new(BTreeMap::new());
13
14/// Configures the logging threshold for a specific module.
15///
16/// If a module is registered here, the logger will respect this level
17/// regardless of the `GLOBAL_FILTER` setting.
18///
19/// # Errors
20/// Returns an error if the logger is already initialized.
21pub fn set_module_filter(module: &str, level: Level) -> Result<(), Box<dyn Error>> {
22  MODULE_FILTERS.write()?.insert(module.to_string(), level);
23  Ok(())
24}
25
26/// The global logger instance, initialized once at runtime.
27static GLOBAL_LOGGER: OnceLock<Box<dyn Dispatcher + Send + Sync>> = OnceLock::new();
28
29/// Initializes the global logger.
30///
31/// # Errors
32/// This function will return an error if the logger has already been initialized.
33pub fn init(dispatcher: Box<dyn Dispatcher + Send + Sync>) -> Result<(), Box<dyn Dispatcher + Send + Sync>> {
34  cirious_codex_term::init_term();
35  GLOBAL_LOGGER.set(dispatcher)
36}
37
38/// Retrieves the global logger, if initialized.
39pub fn get_logger() -> Option<&'static (dyn Dispatcher + Send + Sync)> {
40  GLOBAL_LOGGER.get().map(std::convert::AsRef::as_ref)
41}
42
43// A private helper macro to handle the dispatch logic
44#[macro_export]
45#[doc(hidden)]
46macro_rules! __log_internal {
47  ($level:expr, $($arg:tt)+) => {
48    {
49      let current_level = $level as u8;
50      let module = module_path!();
51
52      let allowed = if let Ok(filters) = $crate::log::MODULE_FILTERS.read() {
53        if let Some(mod_level) = filters.get(module) {
54          current_level >= (*mod_level as u8)
55        } else {
56          current_level >= $crate::log::GLOBAL_FILTER.load(std::sync::atomic::Ordering::Relaxed)
57        }
58      } else {
59        current_level >= $crate::log::GLOBAL_FILTER.load(std::sync::atomic::Ordering::Relaxed)
60      };
61
62      if allowed {
63        if let Some(logger) = $crate::get_logger() {
64          let record = $crate::format::Record {
65            level: $level,
66            args: format!($($arg)+),
67            file: file!(),
68            line: line!(),
69            module_path: module,
70            timestamp: std::time::SystemTime::now(),
71          };
72          let _ = logger.dispatch(&record);
73        }
74      }
75    }
76  };
77}
78
79/// Logs a message at the error level.
80///
81/// Use this macro to log critical failures that prevent a component or the
82/// entire application from continuing normal execution.
83#[macro_export]
84macro_rules! error { ($($arg:tt)+) => { $crate::__log_internal!($crate::level::Level::Error, $($arg)+); } }
85
86/// Logs a message at the warn level.
87///
88/// Use this macro to log hazardous situations or anomalies that are not
89/// fatal but should be investigated by the operations team.
90#[macro_export]
91macro_rules! warn  { ($($arg:tt)+) => { $crate::__log_internal!($crate::level::Level::Warn,  $($arg)+); } }
92
93/// Logs a message at the info level.
94///
95/// Use this macro to record standard, high-level operational events like
96/// startups, shutdowns, or significant milestones in your logic.
97#[macro_export]
98macro_rules! info  { ($($arg:tt)+) => { $crate::__log_internal!($crate::level::Level::Info,  $($arg)+); } }
99
100/// Logs a message at the debug level.
101///
102/// Use this macro to log detailed diagnostic information useful for
103/// developers attempting to understand internal program state or logic flow.
104#[macro_export]
105macro_rules! debug { ($($arg:tt)+) => { $crate::__log_internal!($crate::level::Level::Debug, $($arg)+); } }
106
107/// Logs a message at the trace level.
108///
109/// Use this macro for extremely verbose logging, such as printing variables
110/// inside tight loops, entering/exiting functions, or very granular details.
111#[macro_export]
112macro_rules! trace { ($($arg:tt)+) => { $crate::__log_internal!($crate::level::Level::Trace, $($arg)+); } }