@@ -68,6 +68,7 @@ pub struct Subscriber<C, N = format::DefaultFields, E = format::Format, W = fn()
68
68
fmt_event : E ,
69
69
fmt_span : format:: FmtSpanConfig ,
70
70
is_ansi : bool ,
71
+ log_internal_errors : bool ,
71
72
_inner : PhantomData < fn ( C ) > ,
72
73
}
73
74
@@ -117,6 +118,7 @@ where
117
118
fmt_span : self . fmt_span ,
118
119
make_writer : self . make_writer ,
119
120
is_ansi : self . is_ansi ,
121
+ log_internal_errors : self . log_internal_errors ,
120
122
_inner : self . _inner ,
121
123
}
122
124
}
@@ -146,6 +148,7 @@ where
146
148
fmt_span : self . fmt_span ,
147
149
make_writer : self . make_writer ,
148
150
is_ansi : self . is_ansi ,
151
+ log_internal_errors : self . log_internal_errors ,
149
152
_inner : self . _inner ,
150
153
}
151
154
}
@@ -181,6 +184,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
181
184
fmt_event : self . fmt_event ,
182
185
fmt_span : self . fmt_span ,
183
186
is_ansi : self . is_ansi ,
187
+ log_internal_errors : self . log_internal_errors ,
184
188
make_writer,
185
189
_inner : self . _inner ,
186
190
}
@@ -264,6 +268,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
264
268
fmt_event : self . fmt_event ,
265
269
fmt_span : self . fmt_span ,
266
270
is_ansi : self . is_ansi ,
271
+ log_internal_errors : self . log_internal_errors ,
267
272
make_writer : TestWriter :: default ( ) ,
268
273
_inner : self . _inner ,
269
274
}
@@ -279,6 +284,24 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
279
284
}
280
285
}
281
286
287
+ /// Sets whether to write errors from [`FormatEvent`] to the writer.
288
+ /// Defaults to true.
289
+ ///
290
+ /// By default, `fmt::Subscriber` will write any `FormatEvent`-internal errors to
291
+ /// the writer. These errors are unlikely and will only occur if there is a
292
+ /// bug in the `FormatEvent` implementation or its dependencies.
293
+ ///
294
+ /// If writing to the writer fails, the error message is printed to stderr
295
+ /// as a fallback.
296
+ ///
297
+ /// [`FormatEvent`]: crate::fmt::FormatEvent
298
+ pub fn log_internal_errors ( self , log_internal_errors : bool ) -> Self {
299
+ Self {
300
+ log_internal_errors,
301
+ ..self
302
+ }
303
+ }
304
+
282
305
/// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
283
306
///
284
307
/// This sets the [`MakeWriter`] that the subscriber being built will use to write events.
@@ -307,6 +330,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
307
330
fmt_event : self . fmt_event ,
308
331
fmt_span : self . fmt_span ,
309
332
is_ansi : self . is_ansi ,
333
+ log_internal_errors : self . log_internal_errors ,
310
334
make_writer : f ( self . make_writer ) ,
311
335
_inner : self . _inner ,
312
336
}
@@ -338,6 +362,7 @@ where
338
362
fmt_span : self . fmt_span ,
339
363
make_writer : self . make_writer ,
340
364
is_ansi : self . is_ansi ,
365
+ log_internal_errors : self . log_internal_errors ,
341
366
_inner : self . _inner ,
342
367
}
343
368
}
@@ -350,6 +375,7 @@ where
350
375
fmt_span : self . fmt_span . without_time ( ) ,
351
376
make_writer : self . make_writer ,
352
377
is_ansi : self . is_ansi ,
378
+ log_internal_errors : self . log_internal_errors ,
353
379
_inner : self . _inner ,
354
380
}
355
381
}
@@ -481,6 +507,7 @@ where
481
507
fmt_span : self . fmt_span ,
482
508
make_writer : self . make_writer ,
483
509
is_ansi : self . is_ansi ,
510
+ log_internal_errors : self . log_internal_errors ,
484
511
_inner : self . _inner ,
485
512
}
486
513
}
@@ -495,6 +522,7 @@ where
495
522
fmt_span : self . fmt_span ,
496
523
make_writer : self . make_writer ,
497
524
is_ansi : self . is_ansi ,
525
+ log_internal_errors : self . log_internal_errors ,
498
526
_inner : self . _inner ,
499
527
}
500
528
}
@@ -524,6 +552,7 @@ where
524
552
make_writer : self . make_writer ,
525
553
// always disable ANSI escapes in JSON mode!
526
554
is_ansi : false ,
555
+ log_internal_errors : self . log_internal_errors ,
527
556
_inner : self . _inner ,
528
557
}
529
558
}
@@ -590,6 +619,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
590
619
fmt_span : self . fmt_span ,
591
620
make_writer : self . make_writer ,
592
621
is_ansi : self . is_ansi ,
622
+ log_internal_errors : self . log_internal_errors ,
593
623
_inner : self . _inner ,
594
624
}
595
625
}
@@ -620,6 +650,7 @@ impl<C, N, E, W> Subscriber<C, N, E, W> {
620
650
fmt_span : self . fmt_span ,
621
651
make_writer : self . make_writer ,
622
652
is_ansi : self . is_ansi ,
653
+ log_internal_errors : self . log_internal_errors ,
623
654
_inner : self . _inner ,
624
655
}
625
656
}
@@ -633,6 +664,7 @@ impl<C> Default for Subscriber<C> {
633
664
fmt_span : format:: FmtSpanConfig :: default ( ) ,
634
665
make_writer : io:: stdout,
635
666
is_ansi : cfg ! ( feature = "ansi" ) ,
667
+ log_internal_errors : false ,
636
668
_inner : PhantomData ,
637
669
}
638
670
}
@@ -752,6 +784,11 @@ where
752
784
{
753
785
fields. was_ansi = self . is_ansi ;
754
786
extensions. insert ( fields) ;
787
+ } else {
788
+ eprintln ! (
789
+ "[tracing-subscriber] Unable to format the following event, ignoring: {:?}" ,
790
+ attrs
791
+ ) ;
755
792
}
756
793
}
757
794
@@ -898,7 +935,20 @@ where
898
935
. is_ok ( )
899
936
{
900
937
let mut writer = self . make_writer . make_writer_for ( event. metadata ( ) ) ;
901
- let _ = io:: Write :: write_all ( & mut writer, buf. as_bytes ( ) ) ;
938
+ let res = io:: Write :: write_all ( & mut writer, buf. as_bytes ( ) ) ;
939
+ if self . log_internal_errors {
940
+ if let Err ( e) = res {
941
+ eprintln ! ( "[tracing-subscriber] Unable to write an event to the Writer for this Subscriber! Error: {}\n " , e) ;
942
+ }
943
+ }
944
+ } else if self . log_internal_errors {
945
+ let err_msg = format ! ( "Unable to format the following event. Name: {}; Fields: {:?}\n " ,
946
+ event. metadata( ) . name( ) , event. fields( ) ) ;
947
+ let mut writer = self . make_writer . make_writer_for ( event. metadata ( ) ) ;
948
+ let res = io:: Write :: write_all ( & mut writer, err_msg. as_bytes ( ) ) ;
949
+ if let Err ( e) = res {
950
+ eprintln ! ( "[tracing-subscriber] Unable to write an \" event formatting error\" to the Writer for this Subscriber! Error: {}\n " , e) ;
951
+ }
902
952
}
903
953
904
954
buf. clear ( ) ;
@@ -1197,6 +1247,69 @@ mod test {
1197
1247
re. replace_all ( s. as_str ( ) , "timing" ) . to_string ( )
1198
1248
}
1199
1249
1250
+ #[ test]
1251
+ fn format_error_print_to_stderr ( ) {
1252
+ struct AlwaysError ;
1253
+
1254
+ impl std:: fmt:: Debug for AlwaysError {
1255
+ fn fmt ( & self , _f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
1256
+ Err ( std:: fmt:: Error )
1257
+ }
1258
+ }
1259
+
1260
+ let make_writer = MockMakeWriter :: default ( ) ;
1261
+ let subscriber = crate :: fmt:: Subscriber :: builder ( )
1262
+ . with_writer ( make_writer. clone ( ) )
1263
+ . with_level ( false )
1264
+ . with_ansi ( false )
1265
+ . with_timer ( MockTime )
1266
+ . finish ( ) ;
1267
+
1268
+ with_default ( subscriber, || {
1269
+ tracing:: info!( ?AlwaysError ) ;
1270
+ } ) ;
1271
+ let actual = sanitize_timings ( make_writer. get_string ( ) ) ;
1272
+
1273
+ // Only assert the start because the line number and callsite may change.
1274
+ let expected = concat ! (
1275
+ "Unable to format the following event. Name: event " ,
1276
+ file!( ) ,
1277
+ ":"
1278
+ ) ;
1279
+ assert ! (
1280
+ actual. as_str( ) . starts_with( expected) ,
1281
+ "\n actual = {}\n should start with expected = {}\n " ,
1282
+ actual,
1283
+ expected
1284
+ ) ;
1285
+ }
1286
+
1287
+ #[ test]
1288
+ fn format_error_ignore_if_log_internal_errors_is_false ( ) {
1289
+ struct AlwaysError ;
1290
+
1291
+ impl std:: fmt:: Debug for AlwaysError {
1292
+ fn fmt ( & self , _f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
1293
+ Err ( std:: fmt:: Error )
1294
+ }
1295
+ }
1296
+
1297
+ let make_writer = MockMakeWriter :: default ( ) ;
1298
+ let subscriber = crate :: fmt:: Subscriber :: builder ( )
1299
+ . with_writer ( make_writer. clone ( ) )
1300
+ . with_level ( false )
1301
+ . with_ansi ( false )
1302
+ . with_timer ( MockTime )
1303
+ . log_internal_errors ( false )
1304
+ . finish ( ) ;
1305
+
1306
+ with_default ( subscriber, || {
1307
+ tracing:: info!( ?AlwaysError ) ;
1308
+ } ) ;
1309
+ let actual = sanitize_timings ( make_writer. get_string ( ) ) ;
1310
+ assert_eq ! ( "" , actual. as_str( ) ) ;
1311
+ }
1312
+
1200
1313
#[ test]
1201
1314
fn synthesize_span_none ( ) {
1202
1315
let make_writer = MockMakeWriter :: default ( ) ;
0 commit comments