Skip to content

Commit a492cbf

Browse files
committed
feat: implement ngx_log_error! macro
1 parent cc36157 commit a492cbf

File tree

2 files changed

+116
-52
lines changed

2 files changed

+116
-52
lines changed

examples/upstream.rs

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,21 @@ use std::slice;
1313

1414
use ngx::core::{Pool, Status};
1515
use ngx::ffi::{
16-
nginx_version, ngx_atoi, ngx_command_t, ngx_conf_log_error, ngx_conf_t, ngx_connection_t, ngx_event_free_peer_pt,
16+
nginx_version, ngx_atoi, ngx_command_t, ngx_conf_t, ngx_connection_t, ngx_event_free_peer_pt,
1717
ngx_event_get_peer_pt, ngx_http_module_t, ngx_http_upstream_init_peer_pt, ngx_http_upstream_init_pt,
1818
ngx_http_upstream_init_round_robin, ngx_http_upstream_module, ngx_http_upstream_srv_conf_t, ngx_http_upstream_t,
1919
ngx_int_t, ngx_module_t, ngx_peer_connection_t, ngx_str_t, ngx_uint_t, NGX_CONF_NOARGS, NGX_CONF_TAKE1,
20-
NGX_CONF_UNSET, NGX_ERROR, NGX_HTTP_MODULE, NGX_HTTP_UPS_CONF, NGX_LOG_EMERG, NGX_RS_HTTP_SRV_CONF_OFFSET,
20+
NGX_CONF_UNSET, NGX_ERROR, NGX_HTTP_MODULE, NGX_HTTP_UPS_CONF, NGX_RS_HTTP_SRV_CONF_OFFSET,
2121
NGX_RS_MODULE_SIGNATURE,
2222
};
2323
use ngx::http::{
2424
ngx_http_conf_get_module_srv_conf, ngx_http_conf_upstream_srv_conf_immutable,
2525
ngx_http_conf_upstream_srv_conf_mutable, HTTPModule, Merge, MergeConfigError, Request,
2626
};
27-
use ngx::log::DebugMask;
28-
use ngx::{http_upstream_init_peer_pt, ngx_log_debug_http, ngx_log_debug_mask, ngx_null_command, ngx_string};
27+
use ngx::log::{DebugMask, Level};
28+
use ngx::{
29+
http_upstream_init_peer_pt, ngx_log_debug_http, ngx_log_debug_mask, ngx_log_error, ngx_null_command, ngx_string,
30+
};
2931

3032
#[derive(Clone, Copy, Debug)]
3133
#[repr(C)]
@@ -247,12 +249,7 @@ unsafe extern "C" fn ngx_http_upstream_init_custom(
247249
let maybe_conf: Option<*mut SrvConfig> =
248250
ngx_http_conf_upstream_srv_conf_mutable(us, &*addr_of!(ngx_http_upstream_custom_module));
249251
if maybe_conf.is_none() {
250-
ngx_conf_log_error(
251-
NGX_LOG_EMERG as usize,
252-
cf,
253-
0,
254-
"CUSTOM UPSTREAM no upstream srv_conf".as_bytes().as_ptr() as *const c_char,
255-
);
252+
ngx_log_error!(Level::Emerg, cf, "CUSTOM UPSTREAM no upstream srv_conf");
256253
return isize::from(Status::NGX_ERROR);
257254
}
258255
let hccf = maybe_conf.unwrap();
@@ -263,12 +260,7 @@ unsafe extern "C" fn ngx_http_upstream_init_custom(
263260

264261
let init_upstream_ptr = (*hccf).original_init_upstream.unwrap();
265262
if init_upstream_ptr(cf, us) != Status::NGX_OK.into() {
266-
ngx_conf_log_error(
267-
NGX_LOG_EMERG as usize,
268-
cf,
269-
0,
270-
"CUSTOM UPSTREAM failed calling init_upstream".as_bytes().as_ptr() as *const c_char,
271-
);
263+
ngx_log_error!(Level::Emerg, cf, "CUSTOM UPSTREAM failed calling init_upstream");
272264
return isize::from(Status::NGX_ERROR);
273265
}
274266

@@ -296,13 +288,12 @@ unsafe extern "C" fn ngx_http_upstream_commands_set_custom(
296288
let value: &[ngx_str_t] = slice::from_raw_parts((*(*cf).args).elts as *const ngx_str_t, (*(*cf).args).nelts);
297289
let n = ngx_atoi(value[1].data, value[1].len);
298290
if n == (NGX_ERROR as isize) || n == 0 {
299-
ngx_conf_log_error(
300-
NGX_LOG_EMERG as usize,
291+
ngx_log_error!(
292+
Level::Emerg,
301293
cf,
302-
0,
303-
"invalid value \"%V\" in \"%V\" directive".as_bytes().as_ptr() as *const c_char,
294+
"invalid value \"{}\" in \"{}\" directive",
304295
value[1],
305-
&(*cmd).name,
296+
&(*cmd).name
306297
);
307298
return usize::MAX as *mut c_char;
308299
}
@@ -340,14 +331,7 @@ impl HTTPModule for Module {
340331
let mut pool = Pool::from_ngx_pool((*cf).pool);
341332
let conf = pool.alloc_type::<SrvConfig>();
342333
if conf.is_null() {
343-
ngx_conf_log_error(
344-
NGX_LOG_EMERG as usize,
345-
cf,
346-
0,
347-
"CUSTOM UPSTREAM could not allocate memory for config"
348-
.as_bytes()
349-
.as_ptr() as *const c_char,
350-
);
334+
ngx_log_error!(Level::Emerg, cf, "CUSTOM UPSTREAM could not allocate memory for config");
351335
return std::ptr::null_mut();
352336
}
353337

src/log.rs

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,22 @@
55
use std::ffi::CStr;
66
use std::fmt;
77

8-
use crate::ffi::{self, ngx_err_t, ngx_log_error_core, ngx_log_t, ngx_uint_t};
8+
use crate::ffi::{self, ngx_conf_log_error, ngx_err_t, ngx_log_error_core, ngx_log_t, ngx_uint_t};
9+
10+
/// Checks if the message of the specified level should be logged with this logger.
11+
///
12+
/// # Safety
13+
///
14+
/// The function should be called with a valid target pointer.
15+
#[inline]
16+
pub unsafe fn should_log<T: LogTarget>(target: *const T, level: Level) -> bool {
17+
debug_assert!(!target.is_null());
18+
let log = (*target).get_log();
19+
if log.is_null() {
20+
return false;
21+
}
22+
(*log).log_level >= level.into()
23+
}
924

1025
/// Checks if the debug message with the specified mask should be logged with this logger.
1126
///
@@ -29,7 +44,7 @@ pub unsafe fn should_debug<T: LogTarget>(target: *const T, mask: Option<DebugMas
2944
///
3045
/// The function should be called with a valid target pointer.
3146
#[inline]
32-
pub unsafe fn log_error<T: LogTarget>(target: *const T, level: ngx_uint_t, err: ngx_err_t, args: fmt::Arguments<'_>) {
47+
pub unsafe fn log_error<T: LogTarget>(target: *const T, level: Level, err: ngx_err_t, args: fmt::Arguments<'_>) {
3348
debug_assert!(!target.is_null());
3449
if let Some(str) = args.as_str() {
3550
(*target).write_log(level, err, str.as_bytes());
@@ -38,6 +53,35 @@ pub unsafe fn log_error<T: LogTarget>(target: *const T, level: ngx_uint_t, err:
3853
}
3954
}
4055

56+
/// Severity level
57+
#[repr(usize)]
58+
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
59+
pub enum Level {
60+
/// System is unusable
61+
Emerg = ffi::NGX_LOG_EMERG as usize,
62+
/// Action must be taken immediately
63+
Alert = ffi::NGX_LOG_ALERT as usize,
64+
/// Critical conditions
65+
Crit = ffi::NGX_LOG_CRIT as usize,
66+
/// Error conditions
67+
Err = ffi::NGX_LOG_ERR as usize,
68+
/// Warning conditions
69+
Warn = ffi::NGX_LOG_WARN as usize,
70+
/// Normal but significant condition
71+
Notice = ffi::NGX_LOG_NOTICE as usize,
72+
/// Informational messages
73+
Info = ffi::NGX_LOG_INFO as usize,
74+
/// Debug-level messages
75+
Debug = ffi::NGX_LOG_DEBUG as usize,
76+
}
77+
78+
impl From<Level> for ngx_uint_t {
79+
#[inline]
80+
fn from(value: Level) -> Self {
81+
value as ngx_uint_t
82+
}
83+
}
84+
4185
/// Utility trait for nginx structures that contain logger objects
4286
pub trait LogTarget {
4387
/// Default debug mask for this target
@@ -51,10 +95,10 @@ pub trait LogTarget {
5195

5296
/// Low-level implementation for writing byte slice into the nginx logger
5397
#[inline]
54-
fn write_log(&self, level: ngx_uint_t, err: ngx_err_t, message: &[u8]) {
98+
fn write_log(&self, level: Level, err: ngx_err_t, message: &[u8]) {
5599
const FORMAT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"%*s\0") };
56100
let log = self.get_log().cast_mut();
57-
unsafe { ngx_log_error_core(level, log, err, FORMAT.as_ptr(), message.len(), message.as_ptr()) };
101+
unsafe { ngx_log_error_core(level.into(), log, err, FORMAT.as_ptr(), message.len(), message.as_ptr()) };
58102
}
59103
}
60104

@@ -78,6 +122,22 @@ impl LogTarget for ffi::ngx_conf_t {
78122
fn get_log(&self) -> *const ngx_log_t {
79123
self.log
80124
}
125+
126+
#[inline]
127+
fn write_log(&self, level: Level, err: ngx_err_t, msg: &[u8]) {
128+
const FORMAT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"%*s\0") };
129+
if level < Level::Debug {
130+
// ngx_conf_log_error will not mutate the cf argument.
131+
// ngx_log_error_core may mutate the log argument, but cf does not own the log.
132+
let cf = self as *const _ as *mut _;
133+
unsafe { ngx_conf_log_error(level.into(), cf, err, FORMAT.as_ptr(), msg.len(), msg.as_ptr()) };
134+
} else {
135+
// Debug messages don't need the configuration file context
136+
// SAFETY: this should called after `should_log` or `should_debug`, when we already know
137+
// that the log pointer is valid
138+
unsafe { &*self.log }.write_log(level, err, msg);
139+
}
140+
}
81141
}
82142

83143
impl LogTarget for ffi::ngx_event_t {
@@ -92,13 +152,22 @@ impl LogTarget for ffi::ngx_event_t {
92152
}
93153
}
94154

155+
/// Write to logger at a specified [Level].
156+
#[macro_export]
157+
macro_rules! ngx_log_error {
158+
( $level:expr, $log:expr, $($arg:tt)* ) => {
159+
if unsafe { $crate::log::should_log($log, $level) } {
160+
unsafe { $crate::log::log_error($log, $level, 0, format_args!($($arg)*)) };
161+
}
162+
}
163+
}
164+
95165
/// Write to logger at debug level.
96166
#[macro_export]
97167
macro_rules! ngx_log_debug {
98168
( $log:expr, $($arg:tt)* ) => {
99169
if unsafe { $crate::log::should_debug($log, None) } {
100-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
101-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
170+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
102171
}
103172
}
104173
}
@@ -110,8 +179,7 @@ macro_rules! ngx_log_debug {
110179
macro_rules! ngx_log_debug_http {
111180
( $request:expr, $($arg:tt)* ) => {
112181
if unsafe { $crate::log::should_debug($request, None) } {
113-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
114-
unsafe { $crate::log::log_error($request, level, 0, format_args!($($arg)*)) };
182+
unsafe { $crate::log::log_error($request, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
115183
}
116184
}
117185
}
@@ -128,44 +196,37 @@ macro_rules! ngx_log_debug_http {
128196
macro_rules! ngx_log_debug_mask {
129197
( DebugMask::Core, $log:expr, $($arg:tt)* ) => ({
130198
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Core)) } {
131-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
132-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
199+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
133200
}
134201
});
135202
( DebugMask::Alloc, $log:expr, $($arg:tt)* ) => ({
136203
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Alloc)) } {
137-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
138-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
204+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
139205
}
140206
});
141207
( DebugMask::Mutex, $log:expr, $($arg:tt)* ) => ({
142208
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Mutex)) } {
143-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
144-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
209+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
145210
}
146211
});
147212
( DebugMask::Event, $log:expr, $($arg:tt)* ) => ({
148213
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Event)) } {
149-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
150-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
214+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
151215
}
152216
});
153217
( DebugMask::Http, $log:expr, $($arg:tt)* ) => ({
154218
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Http))} {
155-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
156-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
219+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
157220
}
158221
});
159222
( DebugMask::Mail, $log:expr, $($arg:tt)* ) => ({
160223
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Mail)) } {
161-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
162-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
224+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
163225
}
164226
});
165227
( DebugMask::Stream, $log:expr, $($arg:tt)* ) => ({
166228
if unsafe { $crate::log::should_debug($log, Some(DebugMask::Stream)) } {
167-
let level = $crate::ffi::NGX_LOG_DEBUG as $crate::ffi::ngx_uint_t;
168-
unsafe { $crate::log::log_error($log, level, 0, format_args!($($arg)*)) };
229+
unsafe { $crate::log::log_error($log, $crate::log::Level::Debug, 0, format_args!($($arg)*)) };
169230
}
170231
});
171232
}
@@ -247,7 +308,7 @@ mod tests {
247308
&self.log
248309
}
249310

250-
fn write_log(&self, _level: ngx_uint_t, _err: ngx_err_t, message: &[u8]) {
311+
fn write_log(&self, _level: Level, _err: ngx_err_t, message: &[u8]) {
251312
self.buffer.set(message.to_vec());
252313
}
253314
}
@@ -282,4 +343,23 @@ mod tests {
282343
ngx_log_debug_mask!(DebugMask::Alloc, &log, "mask-alloc");
283344
assert_ne!(log.buffer.take(), b"mask-alloc");
284345
}
346+
#[test]
347+
fn test_level() {
348+
let log = MockLog::new(crate::ffi::NGX_LOG_NOTICE);
349+
350+
ngx_log_error!(Level::Warn, &log, "level-warn");
351+
assert_eq!(log.buffer.take(), b"level-warn");
352+
353+
ngx_log_error!(Level::Notice, &log, "level-notice");
354+
assert_eq!(log.buffer.take(), b"level-notice");
355+
356+
ngx_log_error!(Level::Info, &log, "level-info");
357+
assert_ne!(log.buffer.take(), b"level-info");
358+
359+
ngx_log_error!(Level::Debug, &log, "level-debug");
360+
assert_ne!(log.buffer.take(), b"level-debug");
361+
362+
ngx_log_error!(Level::Err, &log, "level-err");
363+
assert_eq!(log.buffer.take(), b"level-err");
364+
}
285365
}

0 commit comments

Comments
 (0)