美文网首页
自己动手实现简单的日志框架

自己动手实现简单的日志框架

作者: 曾泽浩 | 来源:发表于2018-12-04 22:58 被阅读0次

在实际项目开发中,日志是不可或缺的一部分,日志打印能够帮助开发人员定位问题。在开发过程中,开发人员可以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);
    }


}

上面的例子只是简单的例子,可以把一些变量提取到配置文件中,增加灵活性。

上面的例子和表述都是个人的理解,若有不对的地方,请指正。

相关文章

网友评论

      本文标题:自己动手实现简单的日志框架

      本文链接:https://www.haomeiwen.com/subject/eujbcqtx.html