虽然开源社区有不少优秀的日志框架,但咱们学习标准的java日志框架是为了更好的理解其余框架啊(近期项目要用ELK)java
看本身之前写的Log4J简直不忍直视啊啊啊啊,那时还感受自我良好网络
咱们都试过在代码中插入System.out.println方法来进行调试吧,当找出问题根源后就把插入的print语句删除,若又出现问题则需再次插入这些语句,如此反复。那么日志API就是为了解决这个问题而设计的,使用日志的优点:框架
java有标准的日志系统,在java.util.logging包下。由于它不太好用,就出现了各类补充的日志框架,其实我看着也还行,可以应付个人平常使用了ide
看不懂不要紧,码入下面的程序就能够看到日志记录的状况了学习
public class loggerTest { public static void main(String[] args) { // 1. 得到一个全局的日志记录器 Logger global = Logger.getGlobal(); // 2. 日志有七个级别,从高到低分别是:Sever、Warning、Info、Config、Fine、Finer、Finest // 默认级别为INFO,意思只输出前三个级别的记录 global.info("INFO MSG"); global.warning("WARNING MSG"); global.severe("SERVE MSG"); // 3. 可经过setLevel来设置日志级别,来限制其余级别的记录 global.setLevel(Level.WARNING); } } // 控制台输出 // 七月 23, 2021 8:57:17 下午 logging.loggerTest main // 信息: INFO MSG // 七月 23, 2021 8:57:17 下午 logging.loggerTest main // 警告: WARNING MSG // 七月 23, 2021 8:57:17 下午 logging.loggerTest main // 严重: SERVE MSG
记录器是用来 "记录"、定位日志记录的,通常咱们不想把全部的日志都记录到一个全局记录器上,那么咱们就能够自定义一个记录器this
public class loggerTest { // 未被任何变量引用的日志记录器可能被垃圾回收掉,因此采用了静态变量的方式 private static final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");; public static void main(String[] args) { myLogger.info("this is my logger msg"); } }
日志的记录器有相似于
包名继承
的层次结构,父记录器设置了日志级别,那么子记录器就会继承这个级别,因此日志框架的记录器命名都以类名限定设计
java有个叫日志管理器的东西专门来管配置的,java9的配置文件是在 jre/conf/logging.properties。日志管理器在虚拟机启动时就初始化,就是在main方法执行以前调试
咱们能够在启动项目时就指定日志的配置文件:java -Djava.util.logging.config.file=新文件名
日志
也可在项目运行时用System.setProperty("java.util.logging.config.file", file)指定配置文件,并LogManager.getLogManager().readConfiguration()从新初始化日志管理器生效配置(食用配置文件形式很差,其余日志框架的配置在项目根目录,会自动读取的)code
处理器是用于处理记录的(也有日志级别),记录器有ConsoleHandler、FileHandler、SocketHandler。默认状况下记录器将记录发到ConsoleHandler而后输出,如想输出到其余地方就添加其余的处理器。具体流程的话,就是记录器将记录发给本身的处理器和父记录器的处理器,所有记录器的最终祖先是名为 "" 的一个记录器,它有一个ConsoleHandler,因此默认的日志记录都输出到控制台
public class loggerTest { // 静态变量放垃圾回收 private static final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");; public static void main(String[] args) throws IOException { // 文件、控制台处理器 FileHandler fileHandler = new FileHandler(); ConsoleHandler consoleHandler = new ConsoleHandler(); myLogger.addHandler(consoleHandler); // 这条语句在控制台输出了两次 myLogger.addHandler(fileHandler); myLogger.info("add two handler"); } } // 控制台输出 // 七月 23, 2021 9:31:26 下午 logging.loggerTest main // 信息: add two handler // 七月 23, 2021 9:31:26 下午 logging.loggerTest main // 信息: add two handler
怎么会有两条记录?
fileHander是输出文件的(不在控制台输出),日志文件默认保存在用户目录下的javaN.log中,其中N是惟一编号,默认格式为XML
上面说的myLogger发给本身处理器consoleHandler输出,也会发给父处理器输出,因此有两条,可配置userParentHandlers = false,取消使用父处理器
记录器,处理器只能根据日志级别来过滤,而过滤器则更加自由多样化。咱们须要实现Filter接口(注意是Logger下的接口)而后将其交给记录器(是记录器啊,下面标题2.6的才是交给处理器)
public class loggerTest { private static final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");; public static void main(String[] args) throws IOException { // 过滤器 Filter filter = new Filter() { @Override public boolean isLoggable(LogRecord record) { return record.getMessage().contains("HAHA"); // 记录包含了HAHA就不过滤 } }; myLogger.setFilter(filter); myLogger.info("add two handler"); myLogger.info("i am HAHA"); } } // 控制台输出 // 七月 23, 2021 9:43:27 下午 logging.loggerTest main // 信息: i am HAHA
格式化器顾名思义是用来格式化记录的,看须要生成什么样格式的记录,个人话就在日志前加点东西就行了。也是须要实现format接口的,固然记录的格式化操做是交给处理器的
public class loggerTest { private static final Logger myLogger = Logger.getLogger("com.howl.logger.loggerTest");; public static void main(String[] args) throws IOException { // 格式化器 Formatter formatter = new Formatter() { @Override public String format(LogRecord record) { return "这里是格式化器: "+ record.getMessage() + "\n\n"; } }; ConsoleHandler consoleHandler = new ConsoleHandler(); consoleHandler.setFormatter(formatter); myLogger.addHandler(consoleHandler); myLogger.info("i am HAHA"); } } // 控制台输出 // 这里是格式化器: i am HAHA // // 七月 23, 2021 9:52:58 下午 logging.loggerTest main // 信息: i am HAHA
补丁
使其兼容 JCL 的接口,看着好复杂日志门面 | 组件实现 |
---|---|
JCL、slf4j | log4j、log4j、logback、JUL |
使用框架需选一个日志门面,而后再选择个门面的实现,不选择实现的话默认使用 java 的标准库
笔者还没在项目中实际用过日志框架,体会到的很少,目前只知道 JUL 的配置管理器实属败笔~ 。等笔者搭完此次项目用到的ELK以后再慢慢体会把