在程序员打印日志是一个常见的需求,为此Java提供了内置的Logger类来实现,然而Logger类虽然比较好用,但是它还需要我们自己构造消息体,如果我们利用StackTrace来自动添加调用信息的话,不论是否当前Log级别是否被允许,这些代码都会被执行,显然在生产环境下,这种情况是需要尽量避免的。为了解决这个问题,我们有两种解决方案,其一是扩展Java的Logger类,判断当前Log级别允许时再通过StackTrace来取得调用信息,其二就是利用Java8新引入函数式接口,来实现这一功能。
首先,我们需要定义一个通用的日志类,代码如下所示:
/**
* 采用Java8函数式接口的日志类
* @author 闫涛 2016.06.12
*
*/
public class AppLogger {
public static void log(LogLevel logLevel, Supplier<String> supplier) {
if (logLevel.getLogLevel() >= LOG_LEVEL.getLogLevel()) {
String msg = supplier.get();
StackTraceElement[] stes = new Exception().getStackTrace();
StackTraceElement caller = stes[1];
String methodName = caller.getMethodName();
String className = caller.getClassName();
String lineNumber = "" + caller.getLineNumber();
System.out.println(className + "." + methodName + "(" + lineNumber + "):" + msg);
}
}
/**
* 日志级别枚举类型定义
* @author 闫涛 2016.06.12
*
*/
public static enum LogLevel {
TRACE(1), DEBUG(2), INFO(3), WARNING(4), ERROR(5);
private int logLevel = 0;
private LogLevel(int logLevel) {
this.logLevel = logLevel;
}
public int getLogLevel() {
return logLevel;
}
}
public static LogLevel LOG_LEVEL = LogLevel.INFO;
}
在上面的代码中,我们首先定义了一个LogLevel的枚举类型,定义应用中会用到的日志级别。接着,我们定义一个静态变量LOG_LEVEL来保存当前的日志级别,只有要求打印日志的级别大于或等于本级别时,才会打印相应的内容。
在日志函数中,我们首先判断日志级别是否大于或等于我们定义的允许级别,如果小于则不做任何处理。如果大于,首先通过StackTrace来取出调用者的类名、方法名和行数,然后与要打印的消息进行合并,打印到控制台中。
在程序中需要打印日志时,只需进行如下的调用:
AppLogger.log(AppLogger.LogLevel.INFO, ()->"需要打印的消息");
其会打印出类似如下的内容:
com.haisijia.hxll.simulator.VendorDemo.test(59):需要打印的消息
如果程序部署到生产环境,只需把LOG_LEVEL的值提高到ERROR级别,就可以避免日志打印所带来的性能降低了。同时,还可以动态改变LOG_LEVEL,来临时调试一些BUG。