@@ -117,6 +117,7 @@ pub(crate) struct Builder {
117
117
pub default_format_timestamp_nanos : bool ,
118
118
pub default_format_module_path : bool ,
119
119
pub default_format_level : bool ,
120
+ pub default_format_indent : Option < usize > ,
120
121
#[ allow( unknown_lints, bare_trait_objects) ]
121
122
pub custom_format : Option < Box < Fn ( & mut Formatter , & Record ) -> io:: Result < ( ) > + Sync + Send > > ,
122
123
built : bool ,
@@ -129,6 +130,7 @@ impl Default for Builder {
129
130
default_format_timestamp_nanos : false ,
130
131
default_format_module_path : true ,
131
132
default_format_level : true ,
133
+ default_format_indent : Some ( 4 ) ,
132
134
custom_format : None ,
133
135
built : false ,
134
136
}
@@ -161,6 +163,7 @@ impl Builder {
161
163
module_path : built. default_format_module_path ,
162
164
level : built. default_format_level ,
163
165
written_header_value : false ,
166
+ indent : built. default_format_indent ,
164
167
buf,
165
168
} ;
166
169
@@ -184,6 +187,7 @@ struct DefaultFormat<'a> {
184
187
level : bool ,
185
188
timestamp_nanos : bool ,
186
189
written_header_value : bool ,
190
+ indent : Option < usize > ,
187
191
buf : & ' a mut Formatter ,
188
192
}
189
193
@@ -289,7 +293,54 @@ impl<'a> DefaultFormat<'a> {
289
293
}
290
294
291
295
fn write_args ( & mut self , record : & Record ) -> io:: Result < ( ) > {
292
- writeln ! ( self . buf, "{}" , record. args( ) )
296
+ match self . indent {
297
+
298
+ // Fast path for no indentation
299
+ None => writeln ! ( self . buf, "{}" , record. args( ) ) ,
300
+
301
+ Some ( indent_count) => {
302
+
303
+ // Create a wrapper around the buffer only if we have to actually indent the message
304
+
305
+ struct IndentWrapper < ' a , ' b : ' a > {
306
+ fmt : & ' a mut DefaultFormat < ' b > ,
307
+ indent_count : usize
308
+ }
309
+
310
+ impl < ' a , ' b > Write for IndentWrapper < ' a , ' b > {
311
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
312
+ let mut first = true ;
313
+ for chunk in buf. split ( |& x| x == b'\n' ) {
314
+ if !first {
315
+ write ! ( self . fmt. buf, "\n {:width$}" , "" , width = self . indent_count) ?;
316
+ }
317
+ self . fmt . buf . write_all ( chunk) ?;
318
+ first = false ;
319
+ }
320
+
321
+ Ok ( buf. len ( ) )
322
+ }
323
+
324
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
325
+ self . fmt . buf . flush ( )
326
+ }
327
+ }
328
+
329
+ // The explicit scope here is just to make older versions of Rust happy
330
+ {
331
+ let mut wrapper = IndentWrapper {
332
+ fmt : self ,
333
+ indent_count
334
+ } ;
335
+ write ! ( wrapper, "{}" , record. args( ) ) ?;
336
+ }
337
+
338
+ writeln ! ( self . buf) ?;
339
+
340
+ Ok ( ( ) )
341
+ }
342
+
343
+ }
293
344
}
294
345
}
295
346
@@ -303,7 +354,7 @@ mod tests {
303
354
let buf = fmt. buf . buf . clone ( ) ;
304
355
305
356
let record = Record :: builder ( )
306
- . args ( format_args ! ( "log message " ) )
357
+ . args ( format_args ! ( "log\n message " ) )
307
358
. level ( Level :: Info )
308
359
. file ( Some ( "test.rs" ) )
309
360
. line ( Some ( 144 ) )
@@ -330,10 +381,11 @@ mod tests {
330
381
module_path : true ,
331
382
level : true ,
332
383
written_header_value : false ,
384
+ indent : None ,
333
385
buf : & mut f,
334
386
} ) ;
335
387
336
- assert_eq ! ( "[INFO test::path] log message \n " , written) ;
388
+ assert_eq ! ( "[INFO test::path] log\n message \n " , written) ;
337
389
}
338
390
339
391
#[ test]
@@ -350,9 +402,73 @@ mod tests {
350
402
module_path : false ,
351
403
level : false ,
352
404
written_header_value : false ,
405
+ indent : None ,
406
+ buf : & mut f,
407
+ } ) ;
408
+
409
+ assert_eq ! ( "log\n message\n " , written) ;
410
+ }
411
+
412
+ #[ test]
413
+ fn default_format_indent_spaces ( ) {
414
+ let writer = writer:: Builder :: new ( )
415
+ . write_style ( WriteStyle :: Never )
416
+ . build ( ) ;
417
+
418
+ let mut f = Formatter :: new ( & writer) ;
419
+
420
+ let written = write ( DefaultFormat {
421
+ timestamp : false ,
422
+ timestamp_nanos : false ,
423
+ module_path : true ,
424
+ level : true ,
425
+ written_header_value : false ,
426
+ indent : Some ( 4 ) ,
427
+ buf : & mut f,
428
+ } ) ;
429
+
430
+ assert_eq ! ( "[INFO test::path] log\n message\n " , written) ;
431
+ }
432
+
433
+ #[ test]
434
+ fn default_format_indent_zero_spaces ( ) {
435
+ let writer = writer:: Builder :: new ( )
436
+ . write_style ( WriteStyle :: Never )
437
+ . build ( ) ;
438
+
439
+ let mut f = Formatter :: new ( & writer) ;
440
+
441
+ let written = write ( DefaultFormat {
442
+ timestamp : false ,
443
+ timestamp_nanos : false ,
444
+ module_path : true ,
445
+ level : true ,
446
+ written_header_value : false ,
447
+ indent : Some ( 0 ) ,
448
+ buf : & mut f,
449
+ } ) ;
450
+
451
+ assert_eq ! ( "[INFO test::path] log\n message\n " , written) ;
452
+ }
453
+
454
+ #[ test]
455
+ fn default_format_indent_spaces_no_header ( ) {
456
+ let writer = writer:: Builder :: new ( )
457
+ . write_style ( WriteStyle :: Never )
458
+ . build ( ) ;
459
+
460
+ let mut f = Formatter :: new ( & writer) ;
461
+
462
+ let written = write ( DefaultFormat {
463
+ timestamp : false ,
464
+ timestamp_nanos : false ,
465
+ module_path : false ,
466
+ level : false ,
467
+ written_header_value : false ,
468
+ indent : Some ( 4 ) ,
353
469
buf : & mut f,
354
470
} ) ;
355
471
356
- assert_eq ! ( "log message\n " , written) ;
472
+ assert_eq ! ( "log\n message\n " , written) ;
357
473
}
358
474
}
0 commit comments