自定义实现一个简易日志类

实现要求

  • 至少支持文件输出、控制台输出二种日志输出方式,支持同时输出到文件和控制台
  • 支持DEBUG/INFO/WARN/ERROR四种日志级别

实现步骤

一、定义输出级别枚举类
enum DebugLevel {
    DEBUG(1, "DEBUG"), INFO(2, "INFO"),
    WARN(3, "WARN"), ERROR(4, "ERROR");

    int value;
    String name;

    DebugLevel(int value, String name) {
        this.value = value;
        this.name = name;
    }
}
二、定义输出方式枚举类
enum PrintWay {
    CONSOLE, FILE, BOTH;
}
三、编写输出策略

定义File是为了表示输出目标文件

// 输出策略抽象接口
interface Appender {
    void setPrintWay(PrintWay printWay);
}

// 输出到控制台
class ConsoleAppender implements Appender {

    PrintWay printWay;

    public ConsoleAppender() {
        setPrintWay(PrintWay.CONSOLE);
    }

    @Override
    public void setPrintWay(PrintWay printWay) {
        this.printWay = printWay;
    }
}

// 输出到文件
class FileAppender implements Appender {

    PrintWay printWay;
    File file;

    public FileAppender(String fileName) {
        setPrintWay(PrintWay.FILE);
        this.file = new File(fileName);
    }

    @Override
    public void setPrintWay(PrintWay printWay) {
        this.printWay = printWay;
    }
}

// 同时输出到控制台和文件
class BothAppender implements Appender {

    PrintWay printWay;
    File file;

    public BothAppender(String fileName) {
        setPrintWay(PrintWay.BOTH);
        this.file = new File(fileName);
    }

    @Override
    public void setPrintWay(PrintWay printWay) {
        this.printWay = printWay;
    }
}
四、编写LoggerRepository

用于创建并缓存KLLogger实例

interface LoggerRepository {
    KLLogger getLogger(String className);
}

final class KLLoggerRepository implements LoggerRepository {

    @Override
    public KLLogger getLogger(String className) {
        return new KLLogger(className);
    }
}
五、编写RepositorySelector对象

用于跟踪程序上下文

class RepositorySelector {

    private final LoggerRepository loggerRepository;

    public RepositorySelector(LoggerRepository loggerRepository) {
        this.loggerRepository = loggerRepository;
    }

    public LoggerRepository getLoggerRepository() {
        return loggerRepository;
    }

}
六、编写LogManager对象

用于维护有关Loggers和日志服务的一组共享状态

class KLLoggerManger {

    private static RepositorySelector repositorySelector;

    public static KLLogger getLogger(final String className) {
        return getLoggerRepository().getLogger(className);
    }

    public static LoggerRepository getLoggerRepository() {
        if (Objects.isNull(repositorySelector)) {
            repositorySelector = new RepositorySelector(new KLLoggerRepository());
        }
        return repositorySelector.getLoggerRepository();
    }
}
七、编写日志类
7.1. 编写主要成员变量以及获取日志服务的静态方法
public class KLLogger {
	/**
	 * TODO 日志级别 debug < info < warn < error
	 */
    protected DebugLevel level;
    /**
     * TODO 输出策略
     */
    protected Appender appender;
    /**
     * TODO 类全限定名
     */
    protected String className;

	// 日志时间格式
    protected static final SimpleDateFormat TIME_SECOND = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    // 用户标识占位符
    protected static final char BEGIN_PLACEHOLDER = '{';

	public KLLogger(String className) {
        this.className = className;
    }

	public static KLLogger getLogger(Class clazz) {
        return KLLoggerManger.getLogger(clazz.getName());
    }

    public void setAppender(Appender appender) {
        this.appender = appender;
    }

    public void setLogLevel(DebugLevel level) {
        this.level = level;
    }
}
7.2. 编写日志输出方法
public void debug(String msg) {
   output(new Date(), msg, DebugLevel.DEBUG);
}

public void debug(String msg, Object... var) {
    output(new Date(), msg, DebugLevel.DEBUG, var);
}

public void info(String msg) {
    output(new Date(), msg, DebugLevel.INFO);
}

public void info(String msg, Object... var) {
    output(new Date(), msg, DebugLevel.INFO, var);
}

public void warn(String msg) {
    output(new Date(), msg, DebugLevel.WARN);
}

public void warn(String msg, Object... var) {
    output(new Date(), msg, DebugLevel.WARN, var);
}

public void error(String msg) {
    output(new Date(), msg, DebugLevel.ERROR);
}

public void error(String msg, Object... var) {
    output(new Date(), msg, DebugLevel.ERROR, var);
}
7.3. 编写日志输出选择模式方法
/**
 * 选择输出模式
 * @author Fang Ruichuan
 * @date 2022/6/12 17:04
 * @param curDate       当前时间
 * @param msg           输出语句
 * @param level         日志级别
 * @param args          替换参数
 */
private void output(Date curDate, String msg, DebugLevel level, Object... args) {
    if (Objects.nonNull(args) && args.length != 0) {
        if (this.appender instanceof ConsoleAppender) {
            consoleOutput(curDate, msg, level, args);
        } else if (this.appender instanceof FileAppender) {
            fileOutput(curDate, msg, level, args);
        } else if (this.appender instanceof BothAppender) {
            consoleOutput(curDate, msg, level, args);
            fileOutput(curDate, msg, level, args);
        }
    } else {
        if (this.appender instanceof ConsoleAppender) {
            consoleOutput(curDate, msg, level);
        } else if (this.appender instanceof FileAppender) {
            fileOutput(curDate, msg, level);
        } else if (this.appender instanceof BothAppender) {
            consoleOutput(curDate, msg, level);
            fileOutput(curDate, msg, level);
        }
    }
}
7.4. 编写日志输出到文件方法
/**
* 输出到文件
 * @author Fang Ruichuan
 * @date 2022/6/12 17:06
 * @param curDate   当前时间
 * @param msg       输出语句
 * @param level     日志级别
 * @param args      替换参数
 */
private void fileOutput(Date curDate, String msg, DebugLevel level, Object... args) {
    if (Objects.nonNull(args) && args.length != 0) {
        if (level.value == DebugLevel.DEBUG.value && this.level.value >= level.value) {
            fileVal(curDate, msg, DebugLevel.DEBUG, args);
        }
        if (level.value == DebugLevel.INFO.value && this.level.value >= level.value) {
            fileVal(curDate, msg, DebugLevel.INFO, args);
        }
        if (level.value == DebugLevel.WARN.value && this.level.value >= level.value) {
            fileVal(curDate, msg, DebugLevel.WARN, args);
        }
        if (level.value == DebugLevel.ERROR.value && this.level.value >= level.value) {
            fileVal(curDate, msg, DebugLevel.ERROR, args);
        }
    } else {
        if (level.value == DebugLevel.DEBUG.value && this.level.value >= level.value) {
            file(curDate, msg, DebugLevel.DEBUG);
        }
        if (level.value == DebugLevel.INFO.value && this.level.value >= level.value) {
            file(curDate, msg, DebugLevel.INFO);
        }
        if (level.value == DebugLevel.WARN.value && this.level.value >= level.value) {
            file(curDate, msg, DebugLevel.WARN);
        }
        if (level.value == DebugLevel.ERROR.value && this.level.value >= level.value) {
            file(curDate, msg, DebugLevel.ERROR);
        }
    }
}
// 替换参数并输出到文件
    private void fileVal(Date curDate, String msg, DebugLevel level, Object[] args) {
        File file = getFileFromAppender();
        String line = TIME_SECOND.format(curDate) + " [" + level.name + "] " + this.className + " - " + fillStringByArgs(msg, args);
        writeWithOver(line, file);
    }

    // 直接输出到文件
    private void file(Date curDate, String msg, DebugLevel level) {
        File file = getFileFromAppender();
        String line = TIME_SECOND.format(curDate) + " [" + level.name + "] " + this.className + " - " + msg;
        writeWithOver(line, Objects.requireNonNull(file));
    }

    // 从输出策略中获取文件
    private File getFileFromAppender() {
        File file = null;
        if (this.appender instanceof FileAppender) {
            FileAppender fileAppender = (FileAppender) this.appender;
            file = fileAppender.file;
        } else if (this.appender instanceof BothAppender) {
            BothAppender bothAppender = (BothAppender) this.appender;
            file = bothAppender.file;
        }
        return file;
    }

    /**
     * 将内容追加到文件中并换行
     * @author Fang Ruichuan
     * @date 2022/6/12 17:08
     * @param line          输出内容
     * @param file          目标文件地址
     */
    private void writeWithOver(String line, File file) {
        BufferedWriter writer = null;
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            writer = new BufferedWriter(new FileWriter(file, true));
            writer.write(line);
            writer.newLine();
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(writer)) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
7.5. 编写日志输出到控制台方法
// 输出到控制台
    private void consoleOutput(Date curDate, String msg, DebugLevel level, Object... var) {
        if (Objects.nonNull(var) && var.length != 0) {
            if (level.value == DebugLevel.DEBUG.value && this.level.value >= level.value) {
                printVal(curDate, msg, DebugLevel.DEBUG, var);
            }
            if (level.value == DebugLevel.INFO.value && this.level.value >= level.value) {
                printVal(curDate, msg, DebugLevel.INFO, var);
            }
            if (level.value == DebugLevel.WARN.value && this.level.value >= level.value) {
                printVal(curDate, msg, DebugLevel.WARN, var);
            }
            if (level.value == DebugLevel.ERROR.value && this.level.value >= level.value) {
                printVal(curDate, msg, DebugLevel.ERROR, var);
            }
        } else {
            if (level.value == DebugLevel.DEBUG.value && this.level.value >= level.value) {
                print(curDate, msg, DebugLevel.DEBUG);
            }
            if (level.value == DebugLevel.INFO.value && this.level.value >= level.value) {
                print(curDate, msg, DebugLevel.INFO);
            }
            if (level.value == DebugLevel.WARN.value && this.level.value >= level.value) {
                print(curDate, msg, DebugLevel.WARN);
            }
            if (level.value == DebugLevel.ERROR.value && this.level.value >= level.value) {
                print(curDate, msg, DebugLevel.ERROR);
            }
        }
    }

    private void printVal(Date curDate, String msg, DebugLevel level, Object[] args) {
        System.out.print(TIME_SECOND.format(curDate) + " [" + level.name + "] " + this.className + " - ");
        System.out.println(fillStringByArgs(msg, args));
    }

    private void print(Date curDate, String msg, DebugLevel level) {
        System.out.println(TIME_SECOND.format(curDate) + " [" + level.name + "] " + this.className + " - " + msg);
    }

    /**
     * 将参数数组中按顺序替换到内容中的{}占位符
     * 例1:hello {}, my name is {}     ["frc"]               =>     hello frc, my name is {}
     * 例2:hello {}, my name is {}     ["frc", "yes"]        =>     hello frc, my name is yes
     * 例3:hello {}, my name is {}     ["frc", "yes", "no"]  =>     hello frc, my name is yes
     * @author Fang Ruichuan
     * @date 2022/6/12 17:09
     * @param msg       内容
     * @param args      参数
     * @return String
     */
    private String fillStringByArgs(String msg, Object[] args) {
        int index = 0;
        for (int i = 0; i < msg.length(); i++) {
            char c = msg.charAt(i);
            if (c == BEGIN_PLACEHOLDER && index < args.length) {
                msg = msg.replaceFirst("\\{}", args[index].toString());
                index = index + 1;
            }
        }
        return msg;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值