目录
前言
我们知道自己创建的logger对象,没有继承父元素的话,那其顶级父元素默认就是RootLogger ,它默认日志级别是info,使用的是ConsoleHandler处理器,数据转换用的是SimpleFormatter格式化组件,而这些配置需要我们通过硬编码方式修改,这种方式不太方便后期的管理和维护,因此我们可以通过配置文件的方式进行设置
顶级父元素RootLogger 默认设置
RootLogger对象默认的加载就是配置文件方式,我们可以来通过源码进行查看
1. 获取logger对象时,通过调用 getLogger 构造函数,得到logger实例对象
Logger logger1 = Logger.getLogger("com");
2. 该构造函数底部实际调用的是demandLogger()方法
3. 其方法内部的第一件事就是 获取 LogManager.getLogManager(); 日志管理器对象
4. 日志管理器是一个单例对象,用于加载配置文件的,其内部调用了ensureLogManagerInitialized
5. 继续翻看ensureLogManagerInitialized方法的代码,可以看到有读取配置文件的方法,如下图
6. 俄罗斯套娃,继续点进去查看
7. readConfiguration() 方法,首先会加载,你当前系统类是否有配置类,如果有,则直接加载
8. 如果没有配置类,下方会继续判断,你是否有自定义的配置文件,如果有,则加载你的配置文件,如果还是没有,那么会默认加载 java.home 下的lib文件夹中的 logging.properties 文件
▎debug断点测试
1. 我们在方法内部,读取配置文件位置处进行断点,因为我们没有logger的配置类和自定义配置文件,因此会默认加载java.home文件目录下的文件
2. 使用debug模式运行上述父子类继承特性的测试方法
如下代码在上篇博文《Logger 对象使用详解》中,继承特性里详细贴出来过,主要代码是设置一个logger对象的父类,并修改父类的配置,例如日志级别等,然后通过子类打印日志信息,测试子类继承父类的特性
3. 进入debug代码,可以看到默认配置文件的目录
4. 复制该路径地址,打开访达,Command + shift+G 快捷键,进行搜索该目录
5. 进入lib 目录,找到logging.properites文件,右键打开
6. 配置文件参数如下
# RootLogger顶级父元素指定的默认处理器为:ConsoleHandler和FileHandler(多个处理器之间用逗号隔开)
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
# RootLogger顶级父元素默认的日志级别为:ALL
.level= ALL
# -------------------- 向文件输出的handler对象--------------------
# 指定日志文件路径:%h 当前用户目录,文件名以java开始,%u 是以数字取值
java.util.logging.FileHandler.pattern = %h/java%u.log
# 指定日志文件内容大小,最大为5w条日志
java.util.logging.FileHandler.limit = 50000
# 指定日志文件数量:如果设置为10,则pattern日志文件的命名中的%u取值是 0-9之间
java.util.logging.FileHandler.count = 1
# 指定日志消息格式对象:日志内容将以XML的形式输出到文件中
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# -------------------- 向控制台输出的handler对象--------------------
# 指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定日志消息格式对象:日志内容是简单的文字信息
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
自定义logging.properties文件
上述说了,硬编码的方式配置日志参数,不便于后期维护,因此我们可以通过自定义配置文件方式来加载logger的配置参数
1. 创建日志配置文件,将上述的java.home/lib 目录下的 logging.properties 配置文件复制到resource目录,加以修改即可
2. 编写测试类,进行测试
// 测试resources目录下自定义logging配置文件
@Test
public void test07() throws IOException {
// 1.使用当前类的类加载器读取自定义日志配置文件
InputStream resourceAsStream = LogDemo.class.getClassLoader().getResourceAsStream("logging.properties");
// 2.获取日志管理器(LogManager是单例对象,直接获取即可)
LogManager logManager = LogManager.getLogManager();
// 3.通过日志管理器调用读取配置文件方法
logManager.readConfiguration(resourceAsStream);
// 日志记录器
Logger logger = Logger.getLogger("com.JULTest");
// 输出日志信息
logger.severe("severe:错误信息");
logger.warning("warning:警告信息");
logger.info("info:默认信息");
logger.config("config:配置信息");
logger.fine("fine:详细信息(少)");
logger.finer("finer:详细信息(中)");
logger.finest("finest:详细信息(多)");
}
}
3. 上述测试用例执行结果,下方是ConsoleHandler处理器的执行结果,以标准的日志格式输出到控制台,内部使用的是System.err
4. 由于配置文件中,设置了2个handler处理器,我们再查看FileHandler处理器的输出结果,在当前用户目录下,找到日志文件
该日志文件的命名格式是配置文件中 FileHandler.pattern 参数
5. 点击查看文件内容,以XML格式输出的日志
▎ConsoleHandler 配置
自定义配置文件中,只设置了日志级别和数据转换类,实际还可以设置其他参数,如编码字符集、过滤器,我们可以通过该类进行查看具体配置参数
例如配置编码字符集
# 指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定 handler 对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# 指定 handler 对象的字符集编码
java.util.logging.ConsoleHandler.encoding=UTF-8
★ SimpleFormatter数据转换
格式化组件也可以设置其格式,例如:
配置文件设置方式
# 指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定 handler 对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# 指定 handler 对象的字符集编码
java.util.logging.ConsoleHandler.encoding=UTF-8
# 指定日志消息格式
java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
执行结果:
▎FileHandler 配置
同样,除了默认的配置参数之外,还能配置其他额外参数,如下
例如XML的格式输出到文件,不方便查看,我们可以修改数据格式化为简单文字信息
# 指定日志文件路径:%h 当前用户目录,文件名以java开始,%u 是以数字取值
java.util.logging.FileHandler.pattern = %h/java%u.log
# 指定日志文件内容大小,最大为5w条日志
java.util.logging.FileHandler.limit = 50000
# 指定日志文件数量:如果设置为10,则pattern日志文件的命名中的%u取值是 0-9之间
java.util.logging.FileHandler.count = 1
# 指定日志消息格式对象:日志内容将以XML的形式输出到文件中
#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# 指定日志消息格式对象:日志内容将以文字信息形式输出到文件中
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
执行test07测试用例结果:
✷ 存在问题:日志内容覆盖
默认的FileHandler处理器配置没有设置日志内容是追加模式,也就是每次执行新的日志打印,都会覆盖原来的内容,导致日志内容丢失。
我们希望的是,每次日志打印以追加的模式进行记录,当达到配置的最大条数5w条后,才执行日志覆盖,那么可以设置.append参数值,如下
# 指定日志文件路径:%h 当前用户目录,文件名以java开始,%u 是以数字取值
java.util.logging.FileHandler.pattern = %h/java%u.log
# 指定日志文件内容大小,最大为5w条日志
java.util.logging.FileHandler.limit = 50000
# 指定日志文件数量:如果设置为10,则pattern日志文件的命名中的%u取值是 0-9之间
java.util.logging.FileHandler.count = 1
# 指定日志消息格式对象:日志内容将以XML的形式输出到文件中
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# 指定以追加方式添加日志内容
java.util.logging.FileHandler.append = true
执行结果:两次运行的日志都被记录下来了,而不是像之前一样覆盖原日志信息
自定义logger对象配置
1. 增加自定义logger对象的配置,如果不自定义,默认使用的是父元素,即RootLogger
# RootLogger顶级父元素指定的默认处理器为:ConsoleHandler和FileHandler(多个处理器之间用逗号隔开)
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
# RootLogger顶级父元素默认的日志级别为:ALL
.level= ALL
# 自定义logger使用:自定义一个名为com.JULTest的logger对象的配置参数
com.JULTest.handlers = java.util.logging.ConsoleHandler
com.JULTest.level = WARNING
# 关闭默认配置:关闭com.JULTest的父类继承特性
com.JULTest.useParentHandlers = false
2. 测试类进行测试
// 测试resources目录下自定义logging配置文件
@Test
public void test07() throws IOException {
// 1.使用当前类的类加载器读取自定义日志配置文件
InputStream resourceAsStream = LogDemo.class.getClassLoader().getResourceAsStream("logging.properties");
// 2.获取日志管理器(LogManager是单例对象,直接获取即可)
LogManager logManager = LogManager.getLogManager();
// 3.通过日志管理器调用读取配置文件方法
logManager.readConfiguration(resourceAsStream);
// 日志记录器:com.JULTest我们在自定义配置文件配置日志级别为warning
Logger logger = Logger.getLogger("com.JULTest");
// 输出日志信息
logger.severe("severe:错误信息");
logger.warning("warning:警告信息");
logger.info("info:默认信息");
logger.config("config:配置信息");
logger.fine("fine:详细信息(少)");
logger.finer("finer:详细信息(中)");
logger.finest("finest:详细信息(多)");
// 日志记录器:默认继承了父元素RootLogger的特性
Logger logger2 = Logger.getLogger("mytest");
// 输出日志信息
logger2.severe("severe:错误信息 mytest");
logger2.warning("warning:警告信息 mytest");
logger2.info("info:默认信息 mytest");
logger2.config("config:配置信息 mytest");
logger2.fine("fine:详细信息(少) mytest");
logger2.finer("finer:详细信息(中) mytest");
logger2.finest("finest:详细信息(多) mytest");
}
执行结果:
➳ 分析:配置文件设置了 RootLogger元素的日志级别为ALL,而 mytest 的logger实例对象继承了父元素RootLogger的特性,因此日志全部打印了,而名为 com.JULTest 的logger实例,在配置文件中设置的日志级别为warning,因此大于warning级别的日志会被打印出来,所以只有2条输出