@@ -5,7 +5,9 @@ use crate::{
5
5
registry:: { self , LookupSpan , SpanRef } ,
6
6
} ;
7
7
use format:: { FmtSpan , TimingDisplay } ;
8
- use std:: { any:: TypeId , cell:: RefCell , fmt, io, marker:: PhantomData , ops:: Deref , time:: Instant } ;
8
+ use std:: {
9
+ any:: TypeId , cell:: RefCell , env, fmt, io, marker:: PhantomData , ops:: Deref , time:: Instant ,
10
+ } ;
9
11
use tracing_core:: {
10
12
field,
11
13
span:: { Attributes , Current , Id , Record } ,
@@ -276,6 +278,15 @@ impl<S, N, E, W> Layer<S, N, E, W> {
276
278
/// Sets whether or not the formatter emits ANSI terminal escape codes
277
279
/// for colors and other text formatting.
278
280
///
281
+ /// When the "ansi" crate feature flag is enabled, ANSI colors are enabled
282
+ /// by default unless the [`NO_COLOR`] environment variable is set to
283
+ /// a non-empty value. If the [`NO_COLOR`] environment variable is set to
284
+ /// any non-empty value, then ANSI colors will be suppressed by default.
285
+ /// The [`with_ansi`] and [`set_ansi`] methods can be used to forcibly
286
+ /// enable ANSI colors, overriding any [`NO_COLOR`] environment variable.
287
+ ///
288
+ /// [`NO_COLOR`]: https://no-color.org/
289
+ ///
279
290
/// Enabling ANSI escapes (calling `with_ansi(true)`) requires the "ansi"
280
291
/// crate feature flag. Calling `with_ansi(true)` without the "ansi"
281
292
/// feature flag enabled will panic if debug assertions are enabled, or
@@ -288,6 +299,9 @@ impl<S, N, E, W> Layer<S, N, E, W> {
288
299
/// ANSI escape codes can ensure that they are not used, regardless of
289
300
/// whether or not other crates in the dependency graph enable the "ansi"
290
301
/// feature flag.
302
+ ///
303
+ /// [`with_ansi`]: Subscriber::with_ansi
304
+ /// [`set_ansi`]: Subscriber::set_ansi
291
305
pub fn with_ansi ( self , ansi : bool ) -> Self {
292
306
#[ cfg( not( feature = "ansi" ) ) ]
293
307
if ansi {
@@ -311,10 +325,10 @@ impl<S, N, E, W> Layer<S, N, E, W> {
311
325
/// By default, `fmt::Layer` will write any `FormatEvent`-internal errors to
312
326
/// the writer. These errors are unlikely and will only occur if there is a
313
327
/// bug in the `FormatEvent` implementation or its dependencies.
314
- ///
328
+ ///
315
329
/// If writing to the writer fails, the error message is printed to stderr
316
330
/// as a fallback.
317
- ///
331
+ ///
318
332
/// [`FormatEvent`]: crate::fmt::FormatEvent
319
333
pub fn log_internal_errors ( self , log_internal_errors : bool ) -> Self {
320
334
Self {
@@ -677,12 +691,16 @@ impl<S, N, E, W> Layer<S, N, E, W> {
677
691
678
692
impl < S > Default for Layer < S > {
679
693
fn default ( ) -> Self {
694
+ // only enable ANSI when the feature is enabled, and the NO_COLOR
695
+ // environment variable is unset or empty.
696
+ let ansi = cfg ! ( feature = "ansi" ) && env:: var ( "NO_COLOR" ) . map_or ( true , |v| v. is_empty ( ) ) ;
697
+
680
698
Layer {
681
699
fmt_fields : format:: DefaultFields :: default ( ) ,
682
700
fmt_event : format:: Format :: default ( ) ,
683
701
fmt_span : format:: FmtSpanConfig :: default ( ) ,
684
702
make_writer : io:: stdout,
685
- is_ansi : cfg ! ( feature = " ansi" ) ,
703
+ is_ansi : ansi,
686
704
log_internal_errors : false ,
687
705
_inner : PhantomData ,
688
706
}
@@ -1288,8 +1306,17 @@ mod test {
1288
1306
let actual = sanitize_timings ( make_writer. get_string ( ) ) ;
1289
1307
1290
1308
// Only assert the start because the line number and callsite may change.
1291
- let expected = concat ! ( "Unable to format the following event. Name: event " , file!( ) , ":" ) ;
1292
- assert ! ( actual. as_str( ) . starts_with( expected) , "\n actual = {}\n should start with expected = {}\n " , actual, expected) ;
1309
+ let expected = concat ! (
1310
+ "Unable to format the following event. Name: event " ,
1311
+ file!( ) ,
1312
+ ":"
1313
+ ) ;
1314
+ assert ! (
1315
+ actual. as_str( ) . starts_with( expected) ,
1316
+ "\n actual = {}\n should start with expected = {}\n " ,
1317
+ actual,
1318
+ expected
1319
+ ) ;
1293
1320
}
1294
1321
1295
1322
#[ test]
@@ -1491,4 +1518,73 @@ mod test {
1491
1518
actual. as_str( )
1492
1519
) ;
1493
1520
}
1521
+
1522
+ // Because we need to modify an environment variable for these test cases,
1523
+ // we do them all in a single test.
1524
+ #[ cfg( feature = "ansi" ) ]
1525
+ #[ test]
1526
+ fn layer_no_color ( ) {
1527
+ const NO_COLOR : & str = "NO_COLOR" ;
1528
+
1529
+ // Restores the previous value of the `NO_COLOR` env variable when
1530
+ // dropped.
1531
+ //
1532
+ // This is done in a `Drop` implementation, rather than just resetting
1533
+ // the value at the end of the test, so that the previous value is
1534
+ // restored even if the test panics.
1535
+ struct RestoreEnvVar ( Result < String , env:: VarError > ) ;
1536
+ impl Drop for RestoreEnvVar {
1537
+ fn drop ( & mut self ) {
1538
+ match self . 0 {
1539
+ Ok ( ref var) => env:: set_var ( NO_COLOR , var) ,
1540
+ Err ( _) => env:: remove_var ( NO_COLOR ) ,
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+ let _saved_no_color = RestoreEnvVar ( env:: var ( NO_COLOR ) ) ;
1546
+
1547
+ let cases: Vec < ( Option < & str > , bool ) > = vec ! [
1548
+ ( Some ( "0" ) , false ) , // any non-empty value disables ansi
1549
+ ( Some ( "off" ) , false ) , // any non-empty value disables ansi
1550
+ ( Some ( "1" ) , false ) ,
1551
+ ( Some ( "" ) , true ) , // empty value does not disable ansi
1552
+ ( None , true ) ,
1553
+ ] ;
1554
+
1555
+ for ( var, ansi) in cases {
1556
+ if let Some ( value) = var {
1557
+ env:: set_var ( NO_COLOR , value) ;
1558
+ } else {
1559
+ env:: remove_var ( NO_COLOR ) ;
1560
+ }
1561
+
1562
+ let layer: Layer < ( ) > = fmt:: Layer :: default ( ) ;
1563
+ assert_eq ! (
1564
+ layer. is_ansi, ansi,
1565
+ "NO_COLOR={:?}; Layer::default().is_ansi should be {}" ,
1566
+ var, ansi
1567
+ ) ;
1568
+
1569
+ // with_ansi should override any `NO_COLOR` value
1570
+ let layer: Layer < ( ) > = fmt:: Layer :: default ( ) . with_ansi ( true ) ;
1571
+ assert ! (
1572
+ layer. is_ansi,
1573
+ "NO_COLOR={:?}; Layer::default().with_ansi(true).is_ansi should be true" ,
1574
+ var
1575
+ ) ;
1576
+
1577
+ // set_ansi should override any `NO_COLOR` value
1578
+ let mut layer: Layer < ( ) > = fmt:: Layer :: default ( ) ;
1579
+ layer. set_ansi ( true ) ;
1580
+ assert ! (
1581
+ layer. is_ansi,
1582
+ "NO_COLOR={:?}; layer.set_ansi(true); layer.is_ansi should be true" ,
1583
+ var
1584
+ ) ;
1585
+ }
1586
+
1587
+ // dropping `_saved_no_color` will restore the previous value of
1588
+ // `NO_COLOR`.
1589
+ }
1494
1590
}
0 commit comments