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}