Logback:仅在记录到真实终端时使用彩色输出

20

在我的Logback配置中,我有以下行:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>%highlight(...) %msg%n</pattern>
  </encoder>
  <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>WARN</level>
  </filter>
</appender>

这样可以使警告和错误以彩色显示在终端上,而主日志文件则可包含更多信息,例如 INFO 和 DEBUG 级别。

通常情况下,这个方法效果不错。但是,当我从 Emacs 或任何其他“并不真正是终端”的程序中运行它时,颜色命令会以 ASCII 转义序列的形式显示出来,例如用于警告突出显示的 ^[[31m。有没有办法让 Logback 仅在连接到真正的终端时使用 ANSI 颜色?

4个回答

36

这里有两个问题:

如何检测是否应该使用颜色

这并不容易。正如这个答案所建议的那样,您可以使用JNI调用isatty来检测是否连接到终端,但这需要大量工作,而且优先级相对较低。

如何在logback中有条件地使用颜色

这实际上非常简单(官方文档),请记住您需要janino才能使其正常工作:

<configuration>
    <appender name="COLOR" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%date] %highlight([%level]) [%logger{10} %file:%line] %msg%n</pattern>
            <!--             ^^^^^^^^^^ -->
        </encoder>
    </appender>
    <appender name="NOCOLOR" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%date] [%level] [%logger{10} %file:%line] %msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <!-- to use enable this mode pass -Dcolor to jvm -->
        <if condition='isDefined("color")'>
            <then>
                    <appender-ref ref="COLOR"/>
            </then>
            <else>
                    <appender-ref ref="NOCOLOR"/>
            </else>
        </if>
    </root>
</configuration>

谢谢。显然,在“root”标签内不允许使用“if”,因此您的配置可能需要更新。 - Eric Duminil

3

如果底层终端不兼容ANSI转义序列,则过滤掉它们实际上非常容易。您无需编写任何代码。

根据Logback文档(这里),您只需要将withJansi属性设置为true,如下:

<configuration debug="true">
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <withJansi>true</withJansi>
    <encoder>
      <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

这就是它。


2
在我的这一侧,我通过创建一个自定义的PatternLayout来找到了一种解决方法。它的工作是通过当终端不支持颜色时,替换默认的颜色转换器为不执行任何操作的转换器。
如下:
  • 我也使用Picocli
  • 根据我的经验,Picocli的ANSI颜色支持检测启发式算法非常好。
我使用它来确定何时应该删除颜色转换器。(但你可以使用任何其他启发式算法或像https://dev59.com/_l0Z5IYBdhLWcg3wzC5W#36790201中那样使用环境变量,而无需janino依赖项)
代码看起来像这样:
/**
 * A Logback Pattern Layout that uses Picocli ANSI color
 * heuristic to apply ANSI color only on the terminal which
 * supports it.
 */
public class ColorAwarePatternLayout extends PatternLayout {
   static {
      if (!Ansi.AUTO.enabled()) { // Usage of Picocli heuristic
          DEFAULT_CONVERTER_MAP.put("black", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("red", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("green", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("yellow", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("blue", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("magenta", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("cyan", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("white", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("gray", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldRed", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldGreen", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldYellow", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldBlue", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldMagenta", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldCyan", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("boldWhite", NoColorConverter.class.getName());
          DEFAULT_CONVERTER_MAP.put("highlight", NoColorConverter.class.getName());
      }
   }
}

public class NoColorConverter<E> extends CompositeConverter<E> {
   @Override
   protected String transform(E event, String in) {
      return in;
   }
}

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="your.package.ColorAwarePatternLayout">
                <pattern>%gray(%30.30logger{0}) %gray(%d) [%highlight(%p)] %m%n</pattern>
            </layout>
        </encoder>
    </appender>

    <root level="WARN">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

请查看:

(请参见https://github.com/eclipse/leshan/pull/1068


1
这里是logback控制台appender的示例;
<pattern>%magenta(%d{HH:mm:ss.SSS}) %highlight([%thread]) %-5level [userId: %X{userId}]  %cyan(%logger{36}) - %blue(%msg%n)</pattern>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接