2.第二章 JUL
2.1JUL简介
JUL全称是(Java Util Logging),它是java原生的日志框架,使用时不需要另外引用第三方的类库,相对于其他的框架使用方便,学习简单,主要使用在小型应用中。
Logger:被称为记录器,应用程序通过获取Logger对象,使用其API来发布日志信息。Logger通常被认为是访问日志系统的入口程序 。
Handler:处理器,每个Logger都会关联一个或者是一组Handler,Logger会将日志交给关联的Handler去做处理,由Handler负责将日志做记录。Handler具体实现了日志的输出位置,比如可以输出到控制台或者是文件中等等。
Filter:过滤器,根据需要定制哪些信息会被记录,哪些信息会被忽略。
Formatter:格式化组件,它负责 对日志中的数据和信息进行转换和格式化,所以它决定了我们输出日志最终的形式。
Level:日志的输出级别,每条日志消息都有一个关联的级别。我们根据输出级别的设置,用来展现最终所呈现的日志信息。根据不同需求,去设置不同的级别。
2.2案例分析
因为JUL是Java原生的日志实现,因此第一步我们先创建一个普通的Java项目,引入JUnit来对日志实现进行测试
JUL提供了两种日志输出的方式
第一种方式:直接调用日志级别的相关方法,方法中传递日志输出信息
第二种方式:使用通用的log方法,然后在里面通过Level类型来定义日志的级别参数,以此搭配日志输出信息的参数
在进行日志输出时,通常我们会以字符串拼接的方式编辑日志输出信息,这种方式存在诸多弊端,如:麻烦、程序效率低、可读性不强,维护成本高,推荐使用动态生成数据的方式进行日志输出信息的编辑。
通过观察JUL的Level类可以了解到,JUL的日志级别有以下几种(级别权重从高到低):
OFF:可用来关闭日志记录(特殊级别)
SEVERE:错误(最高级)
WARNING:警告
INFO:消息
CONFIG:配置
FINE:详细信息(少)
FINER:详细信息(中)
FINEST:详细信息(多、最低级)
ALL:启用所有消息的日志记录(特殊级别)
接下来讲解一下如何自定义日志级别
需要我们对Logger与Handler同时进行设置才会生效
上图可看出,当我们没有自定义日志级别时,默认的日志打印级别为INFO级别以上的日志信息,接下来进行自定义日志级别的设置来看下运行结果:
从上述结果可以看到,不仅同时设置了Logger和Handler的日志级别,并且设置了UseParentHandlers为false,防止日志记录发送到父Logger的Handler处理器中,造成重复打印。
通过上述测试,我们创建的是一个控制台日志处理器ConsoleHandler,接下来我们通过创建文件日志处理器FileHandler来实现将日志输出到具体的磁盘文件中,做到日志的持久化操作。
通过测试结果,我们发现日志成功输出到磁盘文件中,但是是以xml格式的形式进行的输出,因此我们可以为Handler处理器添加一个纯文本格式化的组件
再次进行测试,我们发现日志输出格式变为了我们常见的纯文本输出格式
接下来讲解JUL中Logger之间的“父子关系”,这种父子关系不是我们普遍认为的类之间的继承关系,其关系是通过树状结构存储的,JUL在初始化时会创建一个顶层的RootLogger作为所有Logger的父Logger,根据源码分析如下:
RootLogger是LogManager的内部类,全路径为java.util.logging.LogManager$RootLogger,默认名称为空字符串,以上RootLogger对象作为树状结构的根节点存在,自定义的父子关系通过路径来进行关联,同时也是节点之间的挂载关系,
通过一个测试,我们来了解Logger中的这种父子关系
根据测试结果我们了解到,Logger之间的父子关系确实是通过路径来关联的,并且RootLogger的默认名称确实为空字符串,RootLogger可以被称为所有Logger对象的顶层Logger
再次通过一个测试来了解父Logger的设置对子Logger的影响
通过上述测试,我们了解到父Logger的设置也能够作用到子Logger
再次进行测试,分析父Logger与子Logger同时进行设置,会出现怎么的结果
当我们对子Logger也进行Handler处理器相关设置之后,我们发现,日志的输出级别是以子Logger本身设置的日志级别为准,并且我们还发现,测试过程中,我们没有对子Logger进行logger2.setUseParentHandlers(false)的设置,因此输出的日志信息出现了重复,子Logger的日志记录传递到了父Logger的Handler处理器。
再进行一次测试,当我们把父Logger的设置注释掉,在logger1.setUseParentHandlers(false)以及为true的情况下,日志的输出结果:
由以上测试的结果我们了解到,在父Logger未进行setUseParentHandlers(false)的设置的时候,输出日志信息出现的重复,而设置之后,日志信息未重复,进一步说明了Logger父子关系(树状结构存储)之间的传递关系。
以上所有配置相关操作,都是以Java硬编码的形式进行的,我们可以使用更加清晰,更加专业的一种配置方法——配置文件(如果我们没有添加配置文件,则会使用系统默认的配置文件)源码分析如下:
由此我们找到了JUL的默认配置文件,接下来我们进行自定义配置文件的配置,进行测试分析
2.3总结
JUL日志框架使用方式总结
1.初始化LogManager,LogManager加载logging.properties配置,添加Logger到LogManager
2.从单例LogManager获取Logger
3.设置日志级别Level,在打印的过程中使用到了日志记录的LogRecord类
4.Filter作为过滤器提供了日志级别之外更细粒度的控制
5.Handler日志处理器,决定日志输出位置,例如控制台、文件...
6.Formatter用来格式化输出的组件