java: 自定义java.util.logging.Logger的日志输出格式,输出IDE(ECLIPSE)能自动识别行号的格式

2022-11-16 14:03:14 浏览数 (1)

不好用的 java.util.logging.Logger

我们知道在java环境有很不少第三方提供的日志记录库,比如常用的log4j,其实JDK (1.4 or above)本身也提供了日志输出工具,就是 java.util.logging.Logger.但这个工具吧,用也能用,却不好用,聊胜于无。 对于用惯了log4j的我来说,它不好用, 下是用java.util.logging.Logger输出的日志

代码语言:javascript复制
import org.junit.Test;
import java.util.logging.Logger;

public class LoggerTest {
	@Test
	public void test() {
		Logger logger = Logger.getLogger(LoggerTest.class.getSimpleName());
		logger.info("hello,world");
	}

}

日志输出了两行,还没有显示行号,在开发环境中我找这行日志的输出位置很麻烦啊。

十一月 09, 2022 5:21:39 下午 net.gdface.utils.SimpleConsoleFormatterTest test 信息: hello,world

同样的代码用log4j输出,

代码语言:javascript复制
import org.apache.log4j.Logger;
import org.junit.Test;

public class LoggerTest {

    @Test
    public void testLog4j() {
        Logger logger = Logger.getLogger(LoggerTest.class);
        logger.info("hello,world");
    }

}

[main][INFO ] (LoggerTest.java:13) hello,world

比较就可以看出log4j提供的输出内容更短,但提供了更多有效内容,即代码行号,并且在eclipse等IDE中这个格式的输出可以提供超链直接定位到对应的源码位置,这在开发中就方便多了。

不得不用 java.util.logging.Logger 的时候

所以在一般的开发中我肯定更愿意使用log4j,但是 java.util.logging.Logger 也有它存在的意义,它是JDK内置的,它不需要第三方库支持,这在一些偏底层的中间件开发时就有优势了。

但是 java.util.logging.Logger 的输出实在太不友好了,怎么办?我还是习惯log4j的输出格式啊,可不可以自定义输出格式呢?google一查,还真可以(参见 《How do I create a custom logger Formatter?》)。 java.util.logging.Logger 知道自己不能满足各种环境的输出格式需求,所以它的日志输出格式本来就是可以自定义的,

java.util.logging.Formatter 就是用于提供日志输出格式控制的类,要实现自定义的日志输出格式,只要继承此类,重写format(LogRecord record)方法就可以了。

以下就是我基于Formatter实现的日志输出格式的自定义格式类,它可以输出与log4j完全一样的日志格式。

代码语言:javascript复制
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

/**
 * 为 {@link java.util.logging.Logger}实现自定义的日志输出,可以输出IDE(eclipse)自动识别源码位置的日志格式。方便调试
 * @author guyadong
 * @since 2.7.0
 */
public class SimpleConsoleFormatter extends Formatter {

	@Override
	public String format(LogRecord record) {
		String message = formatMessage(record);
		String throwable = "";
		if (record.getThrown() != null) {
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			pw.println();
			record.getThrown().printStackTrace(pw);
			pw.close();
			throwable = "n"   sw.toString();
		}
		Thread currentThread = Thread.currentThread();
		StackTraceElement stackTrace = currentThread.getStackTrace()[8];
		return String.format("[%s] (%s:%d) %s%sn",
				Thread.currentThread().getName(),
				stackTrace.getFileName(),
				stackTrace.getLineNumber(),
				message,
				throwable);
	}
	/**
	 * 将{@link SimpleConsoleFormatter}实例指定为{@link Logger}的输出格式
	 * @param logger
	 * @return always logger
	 */
	public static Logger installFormatter(Logger logger){
		if(null != logger){
			/** 禁用原输出handler,否则会输出两次 */
			logger.setUseParentHandlers(false);
			ConsoleHandler consoleHandler = new ConsoleHandler();
			consoleHandler.setFormatter(new SimpleConsoleFormatter());
			logger.addHandler(consoleHandler);
		}
		return logger;
	}
}

写个测试代码看看效果:

代码语言:javascript复制
import org.junit.Test;

import net.gdface.logger.SimpleConsoleFormatter;

import java.util.logging.Logger;
public class LoggerTest {
	@Test
	public void test2Logger() {
		/** 
		 * 调用 SimpleConsoleFormatter.installFormatter 
		 * 将SimpleConsoleFormatter实例设置为Logger格式输出控制对象  
		 */
		Logger logger = SimpleConsoleFormatter.installFormatter(Logger.getLogger(LoggerTest.class.getSimpleName()));
		logger.info("hello,world");
	}

}

输出与log4j完全一样,eclipse会自动识别日志中的代码行号,生成跳转的链接,完美。

[main] (LoggerTest.java:12) hello,world

SimpleConsoleFormatter 实现参见码云仓库: (https://gitee.com/l0km/common-java/blob/master/common-base2/src/main/java/net/gdface/logger/SimpleConsoleFormatter.java)

参考资料

《How do I create a custom logger Formatter?》

《How to get Eclipse Console to hyperlink text to source code files?》

0 人点赞