Skip to main content

netoptim_rs/
logging.rs

1//! Logging module for netoptim-rs.
2//!
3//! This module provides optional logging capabilities via `env_logger`.
4//! It is only available when the `std` feature is enabled.
5//!
6//! ## Usage
7//!
8//! ```rust,ignore
9//! use netoptim_rs::logging::init_logger;
10//!
11//! init_logger();
12//! log::info!("Application started");
13//! ```
14//!
15//! Or with custom filter:
16//!
17//! ```rust,ignore
18//! use netoptim_rs::logging::init_logger_with_filter;
19//!
20//! init_logger_with_filter("debug");
21//! log::debug!("Debug message");
22//! ```
23//!
24//!
25//! ## Environment Variables
26//!
27//! - `RUST_LOG`: Controls log level (debug, info, warn, error)
28//! - `RUST_LOG_STYLE`: Controls colored output
29//!
30//! Example:
31//! ```bash
32//! RUST_LOG=debug cargo run --features std
33//! ```
34//!
35#[cfg(feature = "std")]
36use log::LevelFilter;
37
38#[cfg(feature = "std")]
39use std::sync::OnceLock;
40
41#[cfg(feature = "std")]
42static LOGGER_INITIALIZED: OnceLock<()> = OnceLock::new();
43
44/// Initialize the logger with the default filter.
45///
46/// Reads the log level from the `RUST_LOG` environment variable.
47/// If not set, defaults to `info` level.
48///
49/// # Panics
50///
51/// Panics if the logger has already been initialized.
52#[cfg(feature = "std")]
53pub fn init_logger() {
54    LOGGER_INITIALIZED.get_or_init(|| ());
55    env_logger::Builder::from_default_env()
56        .filter_level(LevelFilter::Info)
57        .init();
58}
59
60/// Initialize the logger with a custom filter string.
61///
62/// The filter string follows `env_logger`'s format:
63/// - `debug` - Debug and above
64/// - `info` - Info and above
65/// - `warn` - Warnings and above
66/// - `error` - Errors only
67///
68/// # Panics
69///
70/// Panics if the logger has already been initialized.
71#[cfg(feature = "std")]
72pub fn init_logger_with_filter(filter: &str) {
73    LOGGER_INITIALIZED.get_or_init(|| ());
74    env_logger::Builder::from_default_env()
75        .filter_level(filter.parse().unwrap_or(LevelFilter::Info))
76        .init();
77}
78
79/// Try to initialize the logger without panicking.
80///
81/// Reads the log level from the `RUST_LOG` environment variable.
82/// If not set, defaults to `info` level.
83///
84/// # Errors
85///
86/// Returns an error if the logger has already been initialized.
87#[cfg(feature = "std")]
88pub fn try_init_logger() -> Result<(), log::SetLoggerError> {
89    LOGGER_INITIALIZED.get_or_init(|| ());
90    env_logger::Builder::from_default_env()
91        .filter_level(LevelFilter::Info)
92        .try_init()
93}
94
95/// Try to initialize the logger with a custom filter without panicking.
96///
97/// # Errors
98///
99/// Returns an error if the logger has already been initialized.
100#[cfg(feature = "std")]
101pub fn try_init_logger_with_filter(filter: &str) -> Result<(), log::SetLoggerError> {
102    LOGGER_INITIALIZED.get_or_init(|| ());
103    env_logger::Builder::from_default_env()
104        .filter_level(filter.parse().unwrap_or(LevelFilter::Info))
105        .try_init()
106}
107
108/// Check if the logger has been initialized.
109///
110/// # Returns
111///
112/// `true` if the logger is active, `false` otherwise.
113#[cfg(feature = "std")]
114pub fn is_logger_initialized() -> bool {
115    LOGGER_INITIALIZED.get().is_some()
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_try_init_logger() {
124        let _ = try_init_logger();
125    }
126
127    #[test]
128    fn test_try_init_logger_with_filter() {
129        let _ = try_init_logger_with_filter("debug");
130    }
131
132    #[test]
133    fn test_is_logger_initialized() {
134        let _ = try_init_logger();
135        let initialized = is_logger_initialized();
136        assert!(initialized);
137    }
138}