我们知道在java环境有很不少第三方提供的日志记录库,比如常用的log4j,其实JDK (1.4 or above)本身也提供了日志输出工具,就是 java.util.logging.Logger
.但这个工具吧,用也能用,却不好用,聊胜于无。
对于用惯了log4j的我来说,它不好用,
下是用java.util.logging.Logger
输出的日志
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输出,
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中这个格式的输出可以提供超链直接定位到对应的源码位置,这在开发中就方便多了。
所以在一般的开发中我肯定更愿意使用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完全一样的日志格式。
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%s\n",
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;
}
}
写个测试代码看看效果:
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?》