1
+ use core:: cmp;
2
+ use core:: fmt:: { self , Write } ;
3
+ use core:: mem:: MaybeUninit ;
4
+
5
+ use crate :: ffi:: NGX_MAX_ERROR_STR ;
6
+
7
+ /// Size of the static buffer used to format log messages.
8
+ ///
9
+ /// Approximates the remaining space in `u_char[NGX_MAX_ERROR_STR]` after writing the standard
10
+ /// prefix
11
+ pub const LOG_BUFFER_SIZE : usize = NGX_MAX_ERROR_STR as usize - b"1970/01/01 00:00:00 [info] 1#1: " . len ( ) ;
12
+
1
13
/// Utility function to provide typed checking of the mask's field state.
2
14
#[ inline( always) ]
3
15
pub fn check_mask ( mask : DebugMask , log_level : usize ) -> bool {
@@ -8,6 +20,21 @@ pub fn check_mask(mask: DebugMask, log_level: usize) -> bool {
8
20
true
9
21
}
10
22
23
+ /// Format args into a provided buffer
24
+ // May produce incomplete UTF-8 sequences. But any writes to `ngx_log_t` already can be truncated,
25
+ // so nothing we can do here.
26
+ #[ inline]
27
+ pub fn write_fmt < ' a > ( buf : & ' a mut [ MaybeUninit < u8 > ] , args : fmt:: Arguments < ' _ > ) -> & ' a [ u8 ] {
28
+ if let Some ( str) = args. as_str ( ) {
29
+ str. as_bytes ( )
30
+ } else {
31
+ let mut buf = LogBuf :: from ( buf) ;
32
+ // nothing we can or want to do on errors
33
+ let _ = buf. write_fmt ( args) ;
34
+ buf. filled ( )
35
+ }
36
+ }
37
+
11
38
/// Write to logger at a specified level.
12
39
///
13
40
/// See [Logging](https://nginx.org/en/docs/dev/development_guide.html#logging)
@@ -18,8 +45,8 @@ macro_rules! ngx_log_error {
18
45
let log = $log;
19
46
let level = $level as $crate:: ffi:: ngx_uint_t;
20
47
if level < unsafe { ( * log) . log_level } {
21
- let message = :: std :: format! ( $ ( $arg ) + ) ;
22
- let message = message . as_bytes ( ) ;
48
+ let mut buf = [ const { :: core :: mem :: MaybeUninit :: < u8 > :: uninit ( ) } ; $crate :: log :: LOG_BUFFER_SIZE ] ;
49
+ let message = $crate :: log :: write_fmt ( & mut buf , format_args! ( $ ( $arg ) + ) ) ;
23
50
unsafe {
24
51
$crate:: ffi:: ngx_log_error_core( level, log, 0 , c"%*s" . as_ptr( ) , message. len( ) , message. as_ptr( ) ) ;
25
52
}
@@ -34,8 +61,8 @@ macro_rules! ngx_conf_log_error {
34
61
let cf: * mut $crate:: ffi:: ngx_conf_t = $cf;
35
62
let level = $level as $crate:: ffi:: ngx_uint_t;
36
63
if level < unsafe { ( * ( * cf) . log) . log_level } {
37
- let message = :: std :: format! ( $ ( $arg ) + ) ;
38
- let message = message . as_bytes ( ) ;
64
+ let mut buf = [ const { :: core :: mem :: MaybeUninit :: < u8 > :: uninit ( ) } ; $crate :: log :: LOG_BUFFER_SIZE ] ;
65
+ let message = $crate :: log :: write_fmt ( & mut buf , format_args! ( $ ( $arg ) + ) ) ;
39
66
unsafe {
40
67
$crate:: ffi:: ngx_conf_log_error( level, cf, 0 , c"%*s" . as_ptr( ) , message. len( ) , message. as_ptr( ) ) ;
41
68
}
@@ -50,8 +77,8 @@ macro_rules! ngx_log_debug {
50
77
let log = $log;
51
78
if $crate:: log:: check_mask( $mask, unsafe { ( * log) . log_level } ) {
52
79
let level = $crate:: ffi:: NGX_LOG_DEBUG as $crate:: ffi:: ngx_uint_t;
53
- let message = format! ( $ ( $arg ) + ) ;
54
- let message = message . as_bytes ( ) ;
80
+ let mut buf = [ const { :: core :: mem :: MaybeUninit :: < u8 > :: uninit ( ) } ; $crate :: log :: LOG_BUFFER_SIZE ] ;
81
+ let message = $crate :: log :: write_fmt ( & mut buf , format_args! ( $ ( $arg ) + ) ) ;
55
82
unsafe {
56
83
$crate:: ffi:: ngx_log_error_core( level, log, 0 , c"%*s" . as_ptr( ) , message. len( ) , message. as_ptr( ) ) ;
57
84
}
@@ -161,6 +188,52 @@ impl From<DebugMask> for u32 {
161
188
}
162
189
}
163
190
191
+ /// Minimal subset of unstable core::io::{BorrowedBuf,BorrowedCursor}
192
+ struct LogBuf < ' data > {
193
+ buf : & ' data mut [ MaybeUninit < u8 > ] ,
194
+ filled : usize ,
195
+ }
196
+
197
+ impl < ' data > LogBuf < ' data > {
198
+ pub fn filled ( & self ) -> & ' data [ u8 ] {
199
+ // SAFETY: valid bytes have been written to self.buf[..self.filled]
200
+ unsafe {
201
+ let buf = self . buf . get_unchecked ( ..self . filled ) ;
202
+ // inlined MaybeUninit::slice_assume_init_ref
203
+ & * ( buf as * const [ MaybeUninit < u8 > ] as * const [ u8 ] )
204
+ }
205
+ }
206
+
207
+ pub fn append ( & mut self , buf : & [ u8 ] ) -> & mut Self {
208
+ let n = cmp:: min ( self . buf . len ( ) - self . filled , buf. len ( ) ) ;
209
+ unsafe {
210
+ // SAFETY: The source buf has at least n bytes
211
+ let src = buf. get_unchecked ( ..n) ;
212
+ // SAFETY: &[u8] and &[MaybeUninit<u8>] have the same layout
213
+ let src: & [ MaybeUninit < u8 > ] = core:: mem:: transmute ( src) ;
214
+ // SAFETY: self.buf has at least n bytes available after self.filled
215
+ self . buf
216
+ . get_unchecked_mut ( self . filled ..self . filled + n)
217
+ . copy_from_slice ( src) ;
218
+ }
219
+ self . filled += n;
220
+ self
221
+ }
222
+ }
223
+
224
+ impl < ' data > From < & ' data mut [ MaybeUninit < u8 > ] > for LogBuf < ' data > {
225
+ fn from ( buf : & ' data mut [ MaybeUninit < u8 > ] ) -> Self {
226
+ Self { buf, filled : 0 }
227
+ }
228
+ }
229
+
230
+ impl fmt:: Write for LogBuf < ' _ > {
231
+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
232
+ self . append ( s. as_bytes ( ) ) ;
233
+ Ok ( ( ) )
234
+ }
235
+ }
236
+
164
237
#[ cfg( test) ]
165
238
mod tests {
166
239
0 commit comments