Skip to main content

ig_client/utils/
logger.rs

1use std::env;
2use std::sync::Once;
3use tracing::Level;
4use tracing_subscriber::FmtSubscriber;
5
6static INIT: Once = Once::new();
7/// Sets up the logger for the application.
8///
9/// The logger level is determined by the `LOGLEVEL` environment variable.
10/// If the variable is not set, it defaults to `INFO`.
11pub fn setup_logger() {
12    INIT.call_once(|| {
13        let log_level = env::var("LOGLEVEL")
14            .unwrap_or_else(|_| "INFO".to_string())
15            .to_uppercase();
16
17        let level = match log_level.as_str() {
18            "DEBUG" => Level::DEBUG,
19            "ERROR" => Level::ERROR,
20            "WARN" => Level::WARN,
21            "TRACE" => Level::TRACE,
22            _ => Level::INFO,
23        };
24
25        let subscriber = FmtSubscriber::builder().with_max_level(level).finish();
26
27        tracing::subscriber::set_global_default(subscriber)
28            .expect("Error setting default subscriber");
29
30        tracing::debug!("Log level set to: {}", level);
31    });
32}
33
34#[cfg(test)]
35mod tests_setup_logger {
36    use super::setup_logger;
37    use std::env;
38    use tracing::subscriber::set_global_default;
39    use tracing_subscriber::FmtSubscriber;
40
41    #[test]
42    fn test_logger_initialization_info() {
43        unsafe {
44            env::set_var("LOGLEVEL", "INFO");
45        }
46        setup_logger();
47
48        // After setting up the logger, you would typically assert that the logger is working
49        // However, due to the nature of logging, it's difficult to directly assert on log output.
50        // You can, however, check that set_global_default has been called successfully without panic.
51        assert!(
52            set_global_default(FmtSubscriber::builder().finish()).is_err(),
53            "Logger should already be set"
54        );
55    }
56
57    #[test]
58    fn test_logger_initialization_debug() {
59        unsafe {
60            env::set_var("LOGLEVEL", "DEBUG");
61        }
62        setup_logger();
63
64        // Similar to the previous test, check that the global logger has been set
65        assert!(
66            set_global_default(FmtSubscriber::builder().finish()).is_err(),
67            "Logger should already be set"
68        );
69    }
70
71    #[test]
72    fn test_logger_initialization_default() {
73        unsafe {
74            env::remove_var("LOGLEVEL");
75        }
76        setup_logger();
77
78        // Check that the global logger has been set
79        assert!(
80            set_global_default(FmtSubscriber::builder().finish()).is_err(),
81            "Logger should already be set"
82        );
83    }
84
85    #[test]
86    fn test_logger_called_once() {
87        unsafe {
88            env::set_var("LOGLEVEL", "INFO");
89        }
90
91        setup_logger(); // First call should set up the logger
92        setup_logger(); // Second call should not re-initialize
93
94        // Check that the global logger has been set only once
95        assert!(
96            set_global_default(FmtSubscriber::builder().finish()).is_err(),
97            "Logger should already be set and should not be reset"
98        );
99    }
100}
101
102#[cfg(test)]
103mod tests_setup_logger_bis {
104    use super::*;
105    use std::sync::Mutex;
106    use tracing::info;
107    use tracing::subscriber::with_default;
108    use tracing_subscriber::Layer;
109    use tracing_subscriber::layer::SubscriberExt;
110
111    static TEST_MUTEX: Mutex<()> = Mutex::new(());
112
113    #[derive(Clone)]
114    struct TestLayer {
115        level: std::sync::Arc<Mutex<Option<Level>>>,
116    }
117
118    impl<S> Layer<S> for TestLayer
119    where
120        S: tracing::Subscriber,
121    {
122        fn on_event(
123            &self,
124            event: &tracing::Event<'_>,
125            _ctx: tracing_subscriber::layer::Context<'_, S>,
126        ) {
127            if let Ok(mut level) = self.level.lock() {
128                *level = Some(*event.metadata().level());
129            }
130        }
131    }
132
133    fn create_test_layer() -> (TestLayer, std::sync::Arc<Mutex<Option<Level>>>) {
134        let level = std::sync::Arc::new(Mutex::new(None));
135        (
136            TestLayer {
137                level: level.clone(),
138            },
139            level,
140        )
141    }
142
143    #[test]
144    fn test_default_log_level() {
145        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
146        unsafe {
147            env::remove_var("LOGLEVEL");
148        }
149
150        let (layer, level) = create_test_layer();
151        let subscriber = tracing_subscriber::registry().with(layer);
152
153        with_default(subscriber, || {
154            setup_logger();
155            info!("Test log");
156        });
157
158        assert_eq!(
159            *level.lock().expect("Level mutex poisoned"),
160            Some(Level::INFO)
161        );
162    }
163
164    #[test]
165    fn test_debug_log_level() {
166        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
167        unsafe {
168            env::set_var("LOGLEVEL", "DEBUG");
169        }
170
171        let (layer, level) = create_test_layer();
172        let subscriber = tracing_subscriber::registry().with(layer);
173
174        with_default(subscriber, || {
175            setup_logger();
176            tracing::debug!("Test log");
177        });
178
179        assert_eq!(
180            *level.lock().expect("Level mutex poisoned"),
181            Some(Level::DEBUG)
182        );
183
184        unsafe {
185            env::remove_var("LOGLEVEL");
186        }
187    }
188
189    #[test]
190    fn test_error_log_level() {
191        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
192        unsafe {
193            env::set_var("LOGLEVEL", "ERROR");
194        }
195
196        let (layer, level) = create_test_layer();
197        let subscriber = tracing_subscriber::registry().with(layer);
198
199        with_default(subscriber, || {
200            setup_logger();
201            tracing::error!("Test log");
202        });
203
204        assert_eq!(
205            *level.lock().expect("Level mutex poisoned"),
206            Some(Level::ERROR)
207        );
208        unsafe {
209            env::remove_var("LOGLEVEL");
210        }
211    }
212
213    #[test]
214    fn test_warn_log_level() {
215        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
216        unsafe {
217            env::set_var("LOGLEVEL", "WARN");
218        }
219
220        let (layer, level) = create_test_layer();
221        let subscriber = tracing_subscriber::registry().with(layer);
222
223        with_default(subscriber, || {
224            setup_logger();
225            tracing::warn!("Test log");
226        });
227
228        assert_eq!(
229            *level.lock().expect("Level mutex poisoned"),
230            Some(Level::WARN)
231        );
232        unsafe {
233            env::remove_var("LOGLEVEL");
234        }
235    }
236
237    #[test]
238    fn test_trace_log_level() {
239        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
240        unsafe {
241            env::set_var("LOGLEVEL", "TRACE");
242        }
243
244        let (layer, level) = create_test_layer();
245        let subscriber = tracing_subscriber::registry().with(layer);
246
247        with_default(subscriber, || {
248            setup_logger();
249            tracing::trace!("Test log");
250        });
251
252        assert_eq!(
253            *level.lock().expect("Level mutex poisoned"),
254            Some(Level::TRACE)
255        );
256        unsafe {
257            env::remove_var("LOGLEVEL");
258        }
259    }
260
261    #[test]
262    fn test_invalid_log_level() {
263        let _lock = TEST_MUTEX.lock().expect("Test mutex poisoned");
264        unsafe {
265            env::set_var("LOGLEVEL", "INVALID");
266        }
267
268        let (layer, level) = create_test_layer();
269        let subscriber = tracing_subscriber::registry().with(layer);
270
271        with_default(subscriber, || {
272            setup_logger();
273            info!("Test log");
274        });
275
276        assert_eq!(
277            *level.lock().expect("Level mutex poisoned"),
278            Some(Level::INFO)
279        );
280        unsafe {
281            env::remove_var("LOGLEVEL");
282        }
283    }
284}