在实际项目开发中,日志是不可或缺的一部分,日志打印能够帮助开发人员定位问题。在开发过程中,开发人员可以Debug定位问题,但是线上出现问题,这个时候日志就发挥它的作用了。
对于日志,对于每个开发人员都不陌生,从最早的“Hello World!”其实就是最简单的日志打印。从本质上来说,日志也是由每一个打印语句组成的。
最简单的log
System.out.println("我是最简单的日志打印");
尝试加上一些有用的额外信息
- 打印时间
- 线程
- 类名
public static void log(String message) {
String currentThreadName = Thread.currentThread().getName();
String className = SimpleTest.class.getName();
System.out.println(getFormattedDate() + " ["+ currentThreadName+"] " + className + " - "+message);
}
private static String getFormattedDate() {
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("YYYY-MM-dd:HH:mm:ss");
return formatter.format(date);
}
//2018-12-03:17:56:50 [main] SimpleTest - 我是日志打印
- 为log分类,比如INFO、ERROR、DEBUG之类,在实际项目中,通常在开发阶段的日志级别通常是DEBUG级别,项目上线后的日志级别为INFO。
LogLevel
public enum LogLevel {
TRACE(00,"TRACE"),
DEBUG(10,"DEBUG"),
INFO(20,"INFO"),
WARN(30,"WARN"),
ERROR(40,"ERROR");
private int code;
private String desc;
LogLevel(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LogUtils {
static LogLevel DEFAULT_LOG_LEVEL = LogLevel.DEBUG;
public static void main(String[] args) {
String message = "我是日志打印";
log(LogLevel.INFO, message);
log(LogLevel.ERROR, message);
log(LogLevel.WARN,message);
}
public static void log(LogLevel level, String message) {
if (!isLevelEnabled(level)) {
return;
}
String currentThreadName = Thread.currentThread().getName();
String className = LogUtils.class.getName();
System.out.println(level.getDesc() + " "+ getFormattedDate() + " [" + currentThreadName + "] " + className + " - " + message);
}
private static boolean isLevelEnabled(LogLevel level) {
return level.getCode() >= DEFAULT_LOG_LEVEL.getCode();
}
public static void log(String message) {
String currentThreadName = Thread.currentThread().getName();
String className = LogUtils.class.getName();
System.out.println(getFormattedDate() + " [" + currentThreadName + "] " + className + " - " + message);
}
private static String getFormattedDate() {
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("YYYY-MM-dd:HH:mm:ss");
return formatter.format(date);
}
}
//INFO 2018-12-03:18:19:54 [main] LogUtils - 我是日志打印
//ERROR 2018-12-03:18:19:54 [main] LogUtils - 我是日志打印
//WARN 2018-12-03:18:19:54 [main] LogUtils - 我是日志打印
- 多一些控制,Marker。Marker这个词看起来比较奇怪,个人理解,Marker其实就是一个过滤器,在日志级别之前进行过滤,控制更加细级别的日志。
public class Marker {
public static final int SUB = 0;
public static final int TRACE1 = 1 << 0;
public static final int TRACE2 = 1 << 1;
public static final int TRACE3 = 1 << 2;
public static final int TRACE4 = 1 << 3;
public static final int TRACE5 = 1 << 4;
public static final int TRACE6 = 1 << 5;
public static final int TRACE7 = 1 << 6;
public static final int TRACE8 = 1 << 7;
public static final int TRACE9 = 1 << 8;
public static final int TRACE10 = 1 << 9;
public static final int TRACE11 = 1 << 10;
public static final int TRACE12 = 1 << 11;
public static final int TRACE13 = 1 << 12;
public static final int TRACE14 = 1 << 13;
public static final int TRACE15 = 1 << 14;
public static final int TRACE16 = 1 << 15;
public static final int TRACE17 = 1 << 16;
public static final int TRACE18 = 1 << 17;
public static final int TRACE19 = 1 << 18;
public static final int TRACE20 = 1 << 19;
public static final int TRACE21 = 1 << 20;
public static final int TRACE22 = 1 << 21;
public static final int TRACE23 = 1 << 22;
public static final int TRACE34 = 1 << 23;
public static final int TRACE25 = 1 << 24;
public static final int TRACE26 = 1 << 25;
public static final int TRACE27 = 1 << 26;
public static final int TRACE28 = 1 << 27;
public static final int TRACE29 = 1 << 28;
public static final int TRACE30 = 1 << 29;
public static final int TRACE31 = 1 << 20;
}
- 除了控制台打印,输出到其他地方Appender,比如文件。Appender其实就是日志打印的目的地,可以输出到控制台,文件或者其他地方。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LogUtils {
static LogLevel DEFAULT_LOG_LEVEL = LogLevel.DEBUG;
static int DEFAULT_MARKER = Marker.TRACE10;
static PrintStream targetPrintStream = null;
public static void main(String[] args) {
String message = "我是日志打印";
targetPrintStream = getTargetStream("/home/hao/logLearn/test1.txt");
log(LogLevel.INFO, message);
log(LogLevel.ERROR, message);
log(LogLevel.WARN,message);
log(Marker.TRACE10,LogLevel.INFO,message);
}
public static void log(int marker, LogLevel logLevel, String message) {
if (marker == 0 || (marker & DEFAULT_MARKER) != 0 ) {
log(logLevel,message);
}
}
public static void log(LogLevel level, String message) {
if (!isLevelEnabled(level)) {
return;
}
String currentThreadName = Thread.currentThread().getName();
String className = LogUtils.class.getName();
StringBuilder sb = new StringBuilder();
sb.append(level.getDesc()).append(" ").append(getFormattedDate()).append(" [").append(currentThreadName).append("] ")
.append(className).append(" - ").append(message);
targetPrintStream.println(sb.toString());
targetPrintStream.flush();
}
private static PrintStream getTargetStream(String logFile) {
if ("System.out".equalsIgnoreCase(logFile)) {
return System.out;
} else if ("System.err".equalsIgnoreCase(logFile)) {
return System.err;
} else {
try {
FileOutputStream fos = new FileOutputStream(logFile);
PrintStream printStream = new PrintStream(fos);
return printStream;
}catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
private static boolean isLevelEnabled(LogLevel level) {
return level.getCode() >= DEFAULT_LOG_LEVEL.getCode();
}
private static String getFormattedDate() {
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("YYYY-MM-dd:HH:mm:ss");
return formatter.format(date);
}
}
上面的例子只是简单的例子,可以把一些变量提取到配置文件中,增加灵活性。
上面的例子和表述都是个人的理解,若有不对的地方,请指正。
网友评论