Skip to main content

spikard_http/
debug.rs

1//! Debug logging utilities for spikard-http
2//!
3//! This module provides debug logging that can be enabled via:
4//! - Building in debug mode (cfg(debug_assertions))
5//! - Setting SPIKARD_DEBUG=1 environment variable
6
7use std::sync::atomic::{AtomicBool, Ordering};
8
9static DEBUG_ENABLED: AtomicBool = AtomicBool::new(false);
10
11/// Initialize debug logging based on environment and build mode
12pub fn init() {
13    let enabled = cfg!(debug_assertions) || std::env::var("SPIKARD_DEBUG").is_ok() || std::env::var("DEBUG").is_ok();
14
15    eprintln!(
16        "[spikard-http::debug] init() called, cfg!(debug_assertions)={}, DEBUG={}, enabled={}",
17        cfg!(debug_assertions),
18        std::env::var("DEBUG").is_ok(),
19        enabled
20    );
21
22    DEBUG_ENABLED.store(enabled, Ordering::Relaxed);
23
24    if enabled {
25        eprintln!("[spikard-http] Debug logging enabled");
26    }
27}
28
29/// Check if debug logging is enabled
30#[inline]
31pub fn is_enabled() -> bool {
32    DEBUG_ENABLED.load(Ordering::Relaxed)
33}
34
35/// Log a debug message if debugging is enabled
36#[macro_export]
37macro_rules! debug_log {
38    ($($arg:tt)*) => {
39        if $crate::debug::is_enabled() {
40            eprintln!("[spikard-http] {}", format!($($arg)*));
41        }
42    };
43}
44
45/// Log a debug message with a specific module/component name
46#[macro_export]
47macro_rules! debug_log_module {
48    ($module:expr, $($arg:tt)*) => {
49        if $crate::debug::is_enabled() {
50            eprintln!("[spikard-http::{}] {}", $module, format!($($arg)*));
51        }
52    };
53}
54
55/// Log a debug value with pretty-printing
56#[macro_export]
57macro_rules! debug_log_value {
58    ($name:expr, $value:expr) => {
59        if $crate::debug::is_enabled() {
60            eprintln!("[spikard-http] {} = {:?}", $name, $value);
61        }
62    };
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use std::sync::Mutex;
69    use std::sync::atomic::Ordering;
70
71    static FLAG_LOCK: Mutex<()> = Mutex::new(());
72
73    struct DebugFlagGuard {
74        previous_flag: bool,
75        previous_env: Option<String>,
76    }
77
78    impl Drop for DebugFlagGuard {
79        fn drop(&mut self) {
80            DEBUG_ENABLED.store(self.previous_flag, Ordering::Relaxed);
81            if let Some(prev) = &self.previous_env {
82                unsafe { std::env::set_var("SPIKARD_DEBUG", prev) };
83            } else {
84                unsafe { std::env::remove_var("SPIKARD_DEBUG") };
85            }
86        }
87    }
88
89    #[test]
90    fn init_enables_debug_when_requested() {
91        let _lock = FLAG_LOCK.lock().unwrap();
92        let previous = DEBUG_ENABLED.load(Ordering::Relaxed);
93        let previous_env = std::env::var("SPIKARD_DEBUG").ok();
94        let _guard = DebugFlagGuard {
95            previous_flag: previous,
96            previous_env,
97        };
98
99        unsafe { std::env::set_var("SPIKARD_DEBUG", "1") };
100
101        init();
102
103        assert!(is_enabled(), "init should enable debug in test builds");
104    }
105
106    #[test]
107    fn macros_respect_debug_flag() {
108        let _lock = FLAG_LOCK.lock().unwrap();
109        let previous = DEBUG_ENABLED.load(Ordering::Relaxed);
110        let previous_env = std::env::var("SPIKARD_DEBUG").ok();
111        let _guard = DebugFlagGuard {
112            previous_flag: previous,
113            previous_env,
114        };
115
116        DEBUG_ENABLED.store(false, Ordering::Relaxed);
117        debug_log!("should not print while disabled");
118        debug_log_module!("middleware", "disabled branch");
119        debug_log_value!("key", 1_u8);
120        assert!(!is_enabled());
121
122        DEBUG_ENABLED.store(true, Ordering::Relaxed);
123        debug_log!("now printing {}", 2);
124        debug_log_module!("router", "enabled branch");
125        debug_log_value!("value", 3_i32);
126        assert!(is_enabled());
127    }
128}