Eclipse中输出带颜色的log4j日志信息

使用Eclipse开发程序的时候,有时候希望将不同级别的日志在控制台显示成不同的颜色,这样查看起来非常的方便。如果希望控制台显示不同的颜色,需要使用ANSI escape code,比如如果将文本内容(text)使用红色输出,使用如下格式:

"\u001b[" + // 前缀
"0" + // 高亮
";" + // 分隔符
"31" + // 颜色代码(红色)
"m" + // 后缀
text + // 文本内容
"\u001b[m" // 结束符

不过需要说明的是,windows自2000之后控制台不支持ANSI escape code,并且默认的Eclipse控制台也不支持,需要先安装一个名为ANSI Escape in Console的插件,可以直接在Eclipse Marketplace中搜索安装,如果因为网络的问题出现错误可以多尝试几遍。安装完成之后会在Console窗口出现一个ANSIEscapeinConsole-icon小图标,用来控制是否启用ANSI escape code模式。
ANSI Escape in Console

根据上面的规则,可以使用三种方法实现输出带颜色的日志信息:

1. 自定义ConsoleAppender
Dan Dyer实现了一个ANSIConsoleAppender,代码如下:

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Priority;
import org.apache.log4j.spi.LoggingEvent;

/**
* Colour-coded console appender for Log4J.
*/
public class ANSIConsoleAppender extends ConsoleAppender
{
private static final int NORMAL = 0;
private static final int BRIGHT = 1;
private static final int FOREGROUND_BLACK = 30;
private static final int FOREGROUND_RED = 31;
private static final int FOREGROUND_GREEN = 32;
private static final int FOREGROUND_YELLOW = 33;
private static final int FOREGROUND_BLUE = 34;
private static final int FOREGROUND_MAGENTA = 35;
private static final int FOREGROUND_CYAN = 36;
private static final int FOREGROUND_WHITE = 37;

private static final String PREFIX = "\u001b[";
private static final String SUFFIX = "m";
private static final char SEPARATOR = ';';
private static final String END_COLOUR = PREFIX + SUFFIX;

private static final String FATAL_COLOUR = PREFIX
+ BRIGHT + SEPARATOR + FOREGROUND_RED + SUFFIX;
private static final String ERROR_COLOUR = PREFIX
+ NORMAL + SEPARATOR + FOREGROUND_RED + SUFFIX;
private static final String WARN_COLOUR = PREFIX
+ NORMAL + SEPARATOR + FOREGROUND_YELLOW + SUFFIX;
private static final String INFO_COLOUR = PREFIX
+ NORMAL+ SEPARATOR + FOREGROUND_GREEN + SUFFIX;
private static final String DEBUG_COLOUR = PREFIX
+ NORMAL + SEPARATOR + FOREGROUND_CYAN + SUFFIX;
private static final String TRACE_COLOUR = PREFIX
+ NORMAL + SEPARATOR + FOREGROUND_BLUE + SUFFIX;

/**
* Wraps the ANSI control characters around the
* output from the super-class Appender.
*/
protected void subAppend(LoggingEvent event)
{
this.qw.write(getColour(event.getLevel()));
super.subAppend(event);
this.qw.write(END_COLOUR);

if(this.immediateFlush)
{
this.qw.flush();
}
}

/**
* Get the appropriate control characters to change
* the colour for the specified logging level.
*/
private String getColour(Level level)
{
switch (level.toInt())
{
case Priority.FATAL_INT: return FATAL_COLOUR;
case Priority.ERROR_INT: return ERROR_COLOUR;
case Priority.WARN_INT: return WARN_COLOUR;
case Priority.INFO_INT: return INFO_COLOUR;
case Priority.DEBUG_INT:return DEBUG_COLOUR;
default: return TRACE_COLOUR;
}
}
}

可以根据自己的要求调整显示的颜色,这个时候需要在log4j的配置文件将Console设置成上面的ANSIConsoleAppender:
log4j.rootLogger=INFO, Console
log4j.appender.Console=ANSIConsoleAppender

2. 自定义PatternLayout
Ingo Thon实现了一个ColoredPatternLayout(源代码 ColoredPatternLayout.java),内容如下:

/*
* Copyright 2002,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package util.log4j;

import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Level;

import java.util.StringTokenizer;

/**
*

A layout wich has the same functions as the
* Patternlayout.

*

But it also allows to let the output be colored

*

The ColorStrings are formated as follows
* "foreground/background/attribute" where
*

    *

  • foreground and backround is one of
    *

      *

    • black
    • *

    • red
    • *

    • green
    • *

    • yellow
    • *

    • blue
    • *

    • magenta
    • *

    • cyan
    • *

    • white
    • *

    *

  • *

  • attribute is one of
    *

      *

    • normal
    • bright
    • dim
    • *

    • underline
    • blink
    • reverse
    • *

    • hidden
    • *

    *

  • *

    *

*

*

* the following colors could be set
*

    *

  • FatalErrorColor
  • *

  • ErrorColor
  • *

  • WarnColor
  • *

  • InfoColor
  • *

  • DebugColor
  • *

*

*
* major parts of this class came from the apache ant AnsiColorLogger
* @author Ingo Thon isthon a-t gmx d0t de
* @version 0.1 (alpha)
*/
public class ColoredPatternLayout extends PatternLayout{
private static final String CONFIGURATION_SEPARATOR="/";

private static final String PREFIX = "\u001b[";
private static final String SUFFIX = "m";
private static final char SEPARATOR = ';';
private static final String END_COLOR = PREFIX + SUFFIX;

private static final String ATTR_NORMAL = "0";
private static final String ATTR_BRIGHT = "1";
private static final String ATTR_DIM = "2";
private static final String ATTR_UNDERLINE = "3";
private static final String ATTR_BLINK = "5";
private static final String ATTR_REVERSE = "7";
private static final String ATTR_HIDDEN = "8";

private static final String FG_BLACK = "30";
private static final String FG_RED = "31";
private static final String FG_GREEN = "32";
private static final String FG_YELLOW = "33";
private static final String FG_BLUE = "34";
private static final String FG_MAGENTA = "35";
private static final String FG_CYAN = "36";
private static final String FG_WHITE = "37";

private static final String BG_BLACK = "40";
private static final String BG_RED = "41";
private static final String BG_GREEN = "42";
private static final String BG_YELLOW = "44";
private static final String BG_BLUE = "44";
private static final String BG_MAGENTA = "45";
private static final String BG_CYAN = "46";
private static final String BG_WHITE = "47";

private String fatalErrorColor
= PREFIX + ATTR_DIM + SEPARATOR + FG_RED + SUFFIX;
private String errorColor
= PREFIX + ATTR_DIM + SEPARATOR + FG_RED + SUFFIX;
private String warnColor
= PREFIX + ATTR_DIM + SEPARATOR + FG_MAGENTA + SUFFIX;
private String infoColor
= PREFIX + ATTR_DIM + SEPARATOR + FG_GREEN + SUFFIX;
private String debugColor
= PREFIX + ATTR_DIM + SEPARATOR + FG_WHITE + SUFFIX;

public ColoredPatternLayout(){
super();
}
public ColoredPatternLayout(String pattern){
super(pattern);
}

public String format(LoggingEvent event){
if( event.getLevel() == Level.FATAL){
return fatalErrorColor+super.format(event)+END_COLOR;
}else if( event.getLevel() == Level.ERROR){
return errorColor+super.format(event)+END_COLOR;
}if( event.getLevel() == Level.WARN){
return warnColor+super.format(event)+END_COLOR;
}if( event.getLevel() == Level.INFO){
return infoColor+super.format(event)+END_COLOR;
}if( event.getLevel() == Level.DEBUG){
return debugColor+super.format(event)+END_COLOR;
}else{
throw new RuntimeException("Unsupported Level "+event.toString());
}
}
private String makeFgString(String fgColorName){
//System.out.println("fg "+fgColorName);
if(fgColorName.toLowerCase().equals("black")){
return FG_BLACK;
}else if(fgColorName.toLowerCase().equals("red")){
return FG_RED;
}else if(fgColorName.toLowerCase().equals("green")){
return FG_GREEN;
}else if(fgColorName.toLowerCase().equals("yellow")){
return FG_YELLOW;
}else if(fgColorName.toLowerCase().equals("blue")){
return FG_BLUE;
}else if(fgColorName.toLowerCase().equals("magenta")){
return FG_MAGENTA;
}else if(fgColorName.toLowerCase().equals("cyan")){
return FG_CYAN;
}else if(fgColorName.toLowerCase().equals("white")){
return FG_WHITE;
}
System.out.println("log4j: ColoredPatternLayout Unsupported FgColor "+fgColorName);
return "-1";
}
private String makeBgString(String bgColorName){
//System.out.println("bg "+bgColorName);
if(bgColorName.toLowerCase().equals("black")){
return BG_BLACK;
}else if(bgColorName.toLowerCase().equals("red")){
return BG_RED;
}else if(bgColorName.toLowerCase().equals("green")){
return BG_GREEN;
}else if(bgColorName.toLowerCase().equals("yellow")){
return BG_YELLOW;
}else if(bgColorName.toLowerCase().equals("blue")){
return BG_BLUE;
}else if(bgColorName.toLowerCase().equals("magenta")){
return BG_MAGENTA;
}else if(bgColorName.toLowerCase().equals("cyan")){
return BG_CYAN;
}else if(bgColorName.toLowerCase().equals("white")){
return BG_WHITE;
}
System.out.println("log4j: ColoredPatternLayout Unsupported BgColor "+bgColorName);
return "-1";
}

private String makeAttributeString(String attributeName){
//System.out.println("attribute "+attributeName);
if(attributeName.toLowerCase().equals("normal")){
return ATTR_NORMAL;
}else if(attributeName.toLowerCase().equals("bright")){
return ATTR_BRIGHT;
}else if(attributeName.toLowerCase().equals("dim")){
return ATTR_DIM;
}else if(attributeName.toLowerCase().equals("underline")){
return ATTR_UNDERLINE;
}else if(attributeName.toLowerCase().equals("blink")){
return ATTR_BLINK;
}else if(attributeName.toLowerCase().equals("reverse")){
return ATTR_REVERSE;
}else if(attributeName.toLowerCase().equals("hidden")){
return ATTR_HIDDEN;
}
System.out.println("log4j: ColoredPatternLayout Unsupported Attribute "+attributeName);

return "-1";
}

private String makeColorString(String colorName){
//System.out.println(colorName);
StringTokenizer tokenizer=new StringTokenizer(colorName,
CONFIGURATION_SEPARATOR);
String fgColor=FG_WHITE;
String bgColor=BG_BLACK;
String attr=ATTR_NORMAL;
if(!tokenizer.hasMoreTokens()){
return PREFIX + ATTR_NORMAL + SEPARATOR + FG_WHITE + SUFFIX;
}
if(tokenizer.hasMoreTokens()){
fgColor=makeFgString(tokenizer.nextToken());
}
if(tokenizer.hasMoreTokens()){
bgColor=makeBgString(tokenizer.nextToken());
}
if(tokenizer.hasMoreTokens()){
attr=makeAttributeString(tokenizer.nextToken());
}
//return PREFIX + ATTR_DIM + SEPARATOR + FG_WHITE + SUFFIX;
return PREFIX + attr
+ SEPARATOR + fgColor
+ SEPARATOR + bgColor
+SUFFIX;
}
//--> from here configuration {
/** returns the configured color for error msgs
* should normally return only the string for the color
*/
public String getFatalErrorColor(){
return fatalErrorColor;
}
public void setFatalErrorColor(String colorName){
fatalErrorColor=makeColorString(colorName);
}
/** returns the configured color for error msgs
* should normally return only the string for the color
*/
public String getErrorColor(){
return errorColor;
}
public void setErrorColor(String colorName){
//System.out.println(colorName);
errorColor=makeColorString(colorName);
}
/** returns the configured color for error msgs
* should normally return only the string for the color
*/
public String getWarnColor(){
return warnColor;
}
public void setWarnColor(String colorName){
warnColor=makeColorString(colorName);
}
/** returns the configured color for error msgs
* should normally return only the string for the color
*/
public String getInfoColor(){
return infoColor;
}
public void setInfoColor(String colorName){
infoColor=makeColorString(colorName);
}
/** returns the configured color for error msgs
* should normally return only the string for the color
*/
public String getDebugColor(){
return debugColor;
}
public void setDebugColor(String colorName){
//System.out.println(makeColorString(colorName));
debugColor=makeColorString(colorName);
}

//<-- configuration } }
需要在log4j配置文件中设置自定义的layout,并且可以设置各种日志级别的颜色:
log4j.rootLogger=INFO, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=util.log4j.ColoredPatternLayout
log4j.appender.Console.layout.ErrorColor=red
log4j.appender.Console.layout.DebugColor=blue/green/bright

3. 使用jcabi-log的MulticolorLayout
jcabi-log是一个非常不错的日志工具包,基于slf4j,同时也提供了一个用于log4j的layout:MulticolorLayout。首先在maven中引用jcabi-log:


com.jcabi
jcabi-log
0.16


然后在log4j配置文件中启用MulticolorLayout:
log4j.rootLogger=INFO, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=com.jcabi.log.MulticolorLayout
log4j.appender.Console.layout.ConversionPattern=[%color{%-5p}] %c: %m%n

综合来看我觉得方案2最轻量并且可自定义,但如果不是采用log4j的话可以使用jcabi-log包。需要注意的是,如果目标控制器不支持ANSI escape或者生产环境中需要将日志写入到文件中的话不建议使用,否则会增加一些不可识别的字符。

参考资料:
Making a log4j console appender use different colors for different threads
Colored Pattern Layout
Colour-coded Console Logging with Log4J
ANSI Escape in Console (eclipse marketplace)
ANSI的Escape序列屏幕控制码

发表评论

电子邮件地址不会被公开。 必填项已用*标注