nonblocking_logger/utils/
log_util.rs

1use crate::Logger;
2use crate::enums::log_level::LogLevel;
3use std::env;
4use std::io;
5
6/// Parse log level from environment variables
7///
8/// This function checks for log level configuration in the following order:
9/// 1. RUST_LOG environment variable (Rust convention)
10/// 2. LOG_LEVEL environment variable (fallback)
11///
12/// Returns the parsed log level or the default (Info) if not found or invalid.
13pub(crate) fn parse_log_level_from_env() -> LogLevel {
14    if let Ok(rust_log) = env::var("RUST_LOG") {
15        if let Ok(level) = rust_log.parse::<LogLevel>() {
16            return level;
17        }
18    }
19
20    if let Ok(log_level) = env::var("LOG_LEVEL") {
21        if let Ok(level) = log_level.parse::<LogLevel>() {
22            return level;
23        }
24    }
25
26    LogLevel::Info
27}
28
29/// Create a logger configured from environment variables
30///
31/// This function creates a logger with log level determined by environment variables.
32/// It checks RUST_LOG and LOG_LEVEL environment variables in that order.
33pub fn logger_from_env() -> Logger {
34    let level = parse_log_level_from_env();
35    Logger::with_level(level)
36}
37
38/// Create a logger configured from environment variables with stdout target
39pub fn stdout_logger_from_env() -> Logger {
40    logger_from_env().stdout()
41}
42
43/// Create a logger configured from environment variables with stderr target
44pub fn stderr_logger_from_env() -> Logger {
45    logger_from_env().stderr()
46}
47
48/// Create a logger configured from environment variables with file target
49pub fn file_logger_from_env(path: &str) -> io::Result<Logger> {
50    logger_from_env().file(path)
51}
52
53/// Create a simple logger that writes to stdout
54pub fn stdout_logger() -> Logger {
55    Logger::new().stdout()
56}
57
58/// Create a simple logger that writes to stderr
59pub fn stderr_logger() -> Logger {
60    Logger::new().stderr()
61}
62
63/// Create a logger that writes to a file
64pub fn file_logger(path: &str) -> io::Result<Logger> {
65    Logger::new().file(path)
66}
67
68/// Create multiple loggers that write to both stdout and stderr
69pub fn console_loggers() -> Vec<Logger> {
70    vec![Logger::new().stdout(), Logger::new().stderr()]
71}
72
73/// Create a logger with custom time format
74pub fn custom_time_logger(time_format: &str) -> Logger {
75    Logger::new().time_format(time_format).stdout()
76}
77
78/// Log a message to multiple loggers
79///
80/// This function takes a vector of Logger instances and logs the message to all of them.
81pub fn log_to_multiple(loggers: &[Logger], level: LogLevel, message: &str) -> io::Result<()> {
82    for logger in loggers {
83        logger.log_with_level(level, message)?;
84    }
85    Ok(())
86}
87
88/// Log a string message to multiple loggers
89///
90/// This function takes a vector of Logger instances and logs the string message to all of them.
91pub fn log_str_to_multiple(loggers: &[Logger], level: LogLevel, message: &str) -> io::Result<()> {
92    for logger in loggers {
93        logger.log_with_level(level, message)?;
94    }
95    Ok(())
96}
97
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use std::env;
103
104    #[test]
105    fn test_parse_log_level_from_env() {
106        unsafe {
107            env::remove_var("RUST_LOG");
108            env::remove_var("LOG_LEVEL");
109        }
110
111        unsafe {
112            env::set_var("RUST_LOG", "debug");
113        }
114        assert_eq!(parse_log_level_from_env(), LogLevel::Debug);
115
116        unsafe {
117            env::set_var("RUST_LOG", "error");
118        }
119        assert_eq!(parse_log_level_from_env(), LogLevel::Error);
120
121        unsafe {
122            env::set_var("RUST_LOG", "trace");
123        }
124        assert_eq!(parse_log_level_from_env(), LogLevel::Trace);
125
126        unsafe {
127            env::remove_var("RUST_LOG");
128            env::remove_var("LOG_LEVEL");
129            env::set_var("LOG_LEVEL", "warning");
130        }
131        assert_eq!(parse_log_level_from_env(), LogLevel::Warning);
132
133        unsafe {
134            env::remove_var("LOG_LEVEL");
135            env::set_var("RUST_LOG", "DEBUG");
136        }
137        assert_eq!(parse_log_level_from_env(), LogLevel::Debug);
138
139        unsafe {
140            env::set_var("RUST_LOG", "WARN");
141        }
142        assert_eq!(parse_log_level_from_env(), LogLevel::Warning);
143
144        unsafe {
145            env::remove_var("LOG_LEVEL");
146            env::set_var("RUST_LOG", "invalid");
147        }
148        assert_eq!(parse_log_level_from_env(), LogLevel::Info); // Default fallback
149
150        unsafe {
151            env::remove_var("RUST_LOG");
152            env::remove_var("LOG_LEVEL");
153        }
154        assert_eq!(parse_log_level_from_env(), LogLevel::Info);
155
156        unsafe {
157            env::remove_var("RUST_LOG");
158            env::remove_var("LOG_LEVEL");
159        }
160
161        unsafe {
162            env::remove_var("RUST_LOG");
163        }
164
165        unsafe {
166            env::remove_var("RUST_LOG");
167            env::set_var("RUST_LOG", "debug");
168        }
169
170        unsafe {
171            env::remove_var("RUST_LOG");
172            env::set_var("RUST_LOG", " myapp = debug , hyper = info ");
173        }
174
175        unsafe {
176            env::remove_var("RUST_LOG");
177        }
178
179        unsafe {
180            env::remove_var("RUST_LOG");
181            env::remove_var("LOG_LEVEL");
182        }
183
184        unsafe {
185            env::set_var("RUST_LOG", "debug");
186        }
187        let logger = logger_from_env();
188        assert_eq!(logger.get_level(), LogLevel::Debug);
189
190        unsafe {
191            env::remove_var("RUST_LOG");
192            env::set_var("LOG_LEVEL", "error");
193        }
194        let logger = logger_from_env();
195        assert_eq!(logger.get_level(), LogLevel::Error);
196
197        unsafe {
198            env::remove_var("RUST_LOG");
199            env::remove_var("LOG_LEVEL");
200        }
201    }
202
203    #[test]
204    fn test_stdout_logger() -> io::Result<()> {
205        let logger = stdout_logger();
206        assert_eq!(logger.level(), LogLevel::Info);
207
208        logger.info("Test message")?;
209
210        Ok(())
211    }
212
213    #[test]
214    fn test_console_loggers() -> io::Result<()> {
215        let loggers = console_loggers();
216        assert_eq!(loggers.len(), 2);
217
218        log_str_to_multiple(&loggers, LogLevel::Info, "Console message")?;
219
220        for logger in &loggers {
221            assert_eq!(logger.level(), LogLevel::Info);
222        }
223
224        Ok(())
225    }
226
227    #[test]
228    fn test_log_to_multiple() -> io::Result<()> {
229        let loggers = vec![
230            Logger::new().no_time_prefix(),
231            Logger::new().no_time_prefix(),
232        ];
233
234        log_str_to_multiple(&loggers, LogLevel::Info, "Multi-target message")?;
235
236        for logger in &loggers {
237            assert_eq!(logger.level(), LogLevel::Info);
238        }
239
240        Ok(())
241    }
242}