@@ -5,7 +5,9 @@ use crate::{
55 registry:: { self , LookupSpan , SpanRef } ,
66} ;
77use 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+ } ;
911use tracing_core:: {
1012 field,
1113 span:: { Attributes , Current , Id , Record } ,
@@ -276,6 +278,15 @@ impl<S, N, E, W> Layer<S, N, E, W> {
276278 /// Sets whether or not the formatter emits ANSI terminal escape codes
277279 /// for colors and other text formatting.
278280 ///
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+ ///
279290 /// Enabling ANSI escapes (calling `with_ansi(true)`) requires the "ansi"
280291 /// crate feature flag. Calling `with_ansi(true)` without the "ansi"
281292 /// 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> {
288299 /// ANSI escape codes can ensure that they are not used, regardless of
289300 /// whether or not other crates in the dependency graph enable the "ansi"
290301 /// feature flag.
302+ ///
303+ /// [`with_ansi`]: Subscriber::with_ansi
304+ /// [`set_ansi`]: Subscriber::set_ansi
291305 pub fn with_ansi ( self , ansi : bool ) -> Self {
292306 #[ cfg( not( feature = "ansi" ) ) ]
293307 if ansi {
@@ -311,10 +325,10 @@ impl<S, N, E, W> Layer<S, N, E, W> {
311325 /// By default, `fmt::Layer` will write any `FormatEvent`-internal errors to
312326 /// the writer. These errors are unlikely and will only occur if there is a
313327 /// bug in the `FormatEvent` implementation or its dependencies.
314- ///
328+ ///
315329 /// If writing to the writer fails, the error message is printed to stderr
316330 /// as a fallback.
317- ///
331+ ///
318332 /// [`FormatEvent`]: crate::fmt::FormatEvent
319333 pub fn log_internal_errors ( self , log_internal_errors : bool ) -> Self {
320334 Self {
@@ -677,12 +691,16 @@ impl<S, N, E, W> Layer<S, N, E, W> {
677691
678692impl < S > Default for Layer < S > {
679693 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+
680698 Layer {
681699 fmt_fields : format:: DefaultFields :: default ( ) ,
682700 fmt_event : format:: Format :: default ( ) ,
683701 fmt_span : format:: FmtSpanConfig :: default ( ) ,
684702 make_writer : io:: stdout,
685- is_ansi : cfg ! ( feature = " ansi" ) ,
703+ is_ansi : ansi,
686704 log_internal_errors : false ,
687705 _inner : PhantomData ,
688706 }
@@ -1288,8 +1306,17 @@ mod test {
12881306 let actual = sanitize_timings ( make_writer. get_string ( ) ) ;
12891307
12901308 // 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+ ) ;
12931320 }
12941321
12951322 #[ test]
@@ -1491,4 +1518,73 @@ mod test {
14911518 actual. as_str( )
14921519 ) ;
14931520 }
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 subscriber_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 subscriber: Subscriber < ( ) > = fmt:: Subscriber :: default ( ) ;
1563+ assert_eq ! (
1564+ subscriber. is_ansi, ansi,
1565+ "NO_COLOR={:?}; Subscriber::default().is_ansi should be {}" ,
1566+ var, ansi
1567+ ) ;
1568+
1569+ // with_ansi should override any `NO_COLOR` value
1570+ let subscriber: Subscriber < ( ) > = fmt:: Subscriber :: default ( ) . with_ansi ( true ) ;
1571+ assert ! (
1572+ subscriber. is_ansi,
1573+ "NO_COLOR={:?}; Subscriber::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 subscriber: Subscriber < ( ) > = fmt:: Subscriber :: default ( ) ;
1579+ subscriber. set_ansi ( true ) ;
1580+ assert ! (
1581+ subscriber. is_ansi,
1582+ "NO_COLOR={:?}; subscriber.set_ansi(true); subscriber.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+ }
14941590}
0 commit comments