Skip to content

Commit 57c68ff

Browse files
authored
feat: Add debug log mask support (#40)
* feat: Add debug log mask support NGINX supports multiple debug masks to customize logging. We use Rust's type system to represent these as an enum and ease a developer's usage. They can call the ngx_log_debug_mask with any of the supported enum elements. To aid in keeping in sync with NGINX primitives a unit test will fail when the current FIRST and LAST log masks do not align any longer.
1 parent 4aa2e35 commit 57c68ff

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

Diff for: src/log.rs

+178
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/// Utility function to provide typed checking of the mask's field state.
2+
#[inline(always)]
3+
pub fn check_mask(mask: DebugMask, log_level: usize) -> bool {
4+
let mask_bits: u32 = mask.into();
5+
if log_level & mask_bits as usize == 0 {
6+
return false;
7+
}
8+
true
9+
}
10+
111
/// Write to logger at a specified level.
212
///
313
/// See [Logging](https://nginx.org/en/docs/dev/development_guide.html#logging)
@@ -27,3 +37,171 @@ macro_rules! ngx_log_debug_http {
2737
$crate::ngx_log_debug!(log, $($arg)*);
2838
}
2939
}
40+
41+
/// Debug masks for use with ngx_log_debug_mask, these represent the only accepted values for the
42+
/// mask.
43+
#[derive(Debug)]
44+
pub enum DebugMask {
45+
/// Aligns to the NGX_LOG_DEBUG_CORE mask.
46+
Core,
47+
/// Aligns to the NGX_LOG_DEBUG_ALLOC mask.
48+
Alloc,
49+
/// Aligns to the NGX_LOG_DEBUG_MUTEX mask.
50+
Mutex,
51+
/// Aligns to the NGX_LOG_DEBUG_EVENT mask.
52+
Event,
53+
/// Aligns to the NGX_LOG_DEBUG_HTTP mask.
54+
Http,
55+
/// Aligns to the NGX_LOG_DEBUG_MAIL mask.
56+
Mail,
57+
/// Aligns to the NGX_LOG_DEBUG_STREAM mask.
58+
Stream,
59+
}
60+
61+
impl TryFrom<u32> for DebugMask {
62+
type Error = u32;
63+
64+
fn try_from(value: u32) -> Result<Self, Self::Error> {
65+
match value {
66+
crate::ffi::NGX_LOG_DEBUG_CORE => Ok(DebugMask::Core),
67+
crate::ffi::NGX_LOG_DEBUG_ALLOC => Ok(DebugMask::Alloc),
68+
crate::ffi::NGX_LOG_DEBUG_MUTEX => Ok(DebugMask::Mutex),
69+
crate::ffi::NGX_LOG_DEBUG_EVENT => Ok(DebugMask::Event),
70+
crate::ffi::NGX_LOG_DEBUG_HTTP => Ok(DebugMask::Http),
71+
crate::ffi::NGX_LOG_DEBUG_MAIL => Ok(DebugMask::Mail),
72+
crate::ffi::NGX_LOG_DEBUG_STREAM => Ok(DebugMask::Stream),
73+
_ => Err(0),
74+
}
75+
}
76+
}
77+
78+
impl From<DebugMask> for u32 {
79+
fn from(value: DebugMask) -> Self {
80+
match value {
81+
DebugMask::Core => crate::ffi::NGX_LOG_DEBUG_CORE,
82+
DebugMask::Alloc => crate::ffi::NGX_LOG_DEBUG_ALLOC,
83+
DebugMask::Mutex => crate::ffi::NGX_LOG_DEBUG_MUTEX,
84+
DebugMask::Event => crate::ffi::NGX_LOG_DEBUG_EVENT,
85+
DebugMask::Http => crate::ffi::NGX_LOG_DEBUG_HTTP,
86+
DebugMask::Mail => crate::ffi::NGX_LOG_DEBUG_MAIL,
87+
DebugMask::Stream => crate::ffi::NGX_LOG_DEBUG_STREAM,
88+
}
89+
}
90+
}
91+
92+
/// Log with requested debug mask.
93+
///
94+
/// **NOTE:** This macro supports `DebugMask::Http` (`NGX_LOG_DEBUG_HTTP`), however, if you have
95+
/// access to a Request object via an http handler it can be more convenient and readable to use the
96+
/// `ngx_log_debug_http` macro instead.
97+
///
98+
/// See https://nginx.org/en/docs/dev/development_guide.html#logging for details and available
99+
/// masks.
100+
#[macro_export]
101+
macro_rules! ngx_log_debug_mask {
102+
( DebugMask::Core, $log:expr, $($arg:tt)* ) => ({
103+
let log_level = unsafe { (*$log).log_level };
104+
if $crate::log::check_mask(DebugMask::Core, log_level) {
105+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
106+
let fmt = ::std::ffi::CString::new("%s").unwrap();
107+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
108+
unsafe {
109+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
110+
}
111+
}
112+
});
113+
( DebugMask::Alloc, $log:expr, $($arg:tt)* ) => ({
114+
let log_level = unsafe { (*$log).log_level };
115+
if $crate::log::check_mask(DebugMask::Alloc, log_level) {
116+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
117+
let fmt = ::std::ffi::CString::new("%s").unwrap();
118+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
119+
unsafe {
120+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
121+
}
122+
}
123+
});
124+
( DebugMask::Mutex, $log:expr, $($arg:tt)* ) => ({
125+
let log_level = unsafe { (*$log).log_level };
126+
if $crate::log::check_mask(DebugMask::Mutex, log_level) {
127+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
128+
let fmt = ::std::ffi::CString::new("%s").unwrap();
129+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
130+
unsafe {
131+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
132+
}
133+
}
134+
});
135+
( DebugMask::Event, $log:expr, $($arg:tt)* ) => ({
136+
let log_level = unsafe { (*$log).log_level };
137+
if $crate::log::check_mask(DebugMask::Event, log_level) {
138+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
139+
let fmt = ::std::ffi::CString::new("%s").unwrap();
140+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
141+
unsafe {
142+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
143+
}
144+
}
145+
});
146+
( DebugMask::Http, $log:expr, $($arg:tt)* ) => ({
147+
let log_level = unsafe { (*$log).log_level };
148+
if $crate::log::check_mask(DebugMask::Http, log_level) {
149+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
150+
let fmt = ::std::ffi::CString::new("%s").unwrap();
151+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
152+
unsafe {
153+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
154+
}
155+
}
156+
});
157+
( DebugMask::Mail, $log:expr, $($arg:tt)* ) => ({
158+
let log_level = unsafe { (*$log).log_level };
159+
if $crate::log::check_mask(DebugMask::Mail, log_level) {
160+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
161+
let fmt = ::std::ffi::CString::new("%s").unwrap();
162+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
163+
unsafe {
164+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
165+
}
166+
}
167+
});
168+
( DebugMask::Stream, $log:expr, $($arg:tt)* ) => ({
169+
let log_level = unsafe { (*$log).log_level };
170+
if $crate::log::check_mask(DebugMask::Stream, log_level) {
171+
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
172+
let fmt = ::std::ffi::CString::new("%s").unwrap();
173+
let c_message = ::std::ffi::CString::new(format!($($arg)*)).unwrap();
174+
unsafe {
175+
$crate::ffi::ngx_log_error_core(level, $log, 0, fmt.as_ptr(), c_message.as_ptr());
176+
}
177+
}
178+
});
179+
}
180+
181+
#[cfg(test)]
182+
mod tests {
183+
184+
use super::*;
185+
186+
#[test]
187+
fn test_mask_lower_bound() {
188+
assert!(<DebugMask as Into<u32>>::into(DebugMask::Core) == crate::ffi::NGX_LOG_DEBUG_FIRST);
189+
}
190+
#[test]
191+
fn test_mask_upper_bound() {
192+
assert!(<DebugMask as Into<u32>>::into(DebugMask::Stream) == crate::ffi::NGX_LOG_DEBUG_LAST);
193+
}
194+
#[test]
195+
fn test_check_mask() {
196+
struct MockLog {
197+
log_level: usize,
198+
}
199+
let mock = MockLog { log_level: 16 };
200+
201+
let mut r = check_mask(DebugMask::Core, mock.log_level);
202+
assert!(r == true);
203+
204+
r = check_mask(DebugMask::Alloc, mock.log_level);
205+
assert!(r == false);
206+
}
207+
}

0 commit comments

Comments
 (0)