JUL框架(重要)

介绍

是jdk自带的原生让日志框架,所以使用它不需要导入第三方依赖。
在这里插入图片描述

框架体系

1.我们使用提供的Logger对象(java.util包下),去设置日志级别和内容。
2.Logger对象底层调用Handler对象(处理器),将我们日志文件指定输出位置,是程序控制台还是文件里还是网络的路径地址。
3.在输出消息之前,需要通过handler调用Layouts(Formatters)将日志消息进行格式化的转换,最终输出到目标路径。——在此期间可以调用多个filter过滤器进行细密度的日志拦截和过滤的过程。

使用

通过提供的静态方法:getLogger()生成对象。
方法参数:
每个日志记录器都需要一个唯一标识,通常以当前类的全限定名命名
在这里插入图片描述
粘贴进即可:
在这里插入图片描述

level介绍(日志级别)

在这里插入图片描述
这是一个枚举类
一共提供了七个日志级别:(级别从高到低)
1.severe:最高级别
比如程序出现了严重的问题,造成了程序的终止,就可以把server进行接入。
在这里插入图片描述

2.warning:警告信息,记录程序发生的一些问题,这些问题不会造成程序的终止,但是我们也需要进行关注,就使用这个。
在这里插入图片描述

3.info:记录一些数据库的连接信息,传递信息和网络通信的信息等等。(JUL日志级别默认取值)
在这里插入图片描述

4.config:配置信息,比如加载了配置文件,读取了配置文件的一些参数,这时候用这个进行记录。

5.fine,finer,finest:都是debug日志记录的消息,记录程序一些运行状态,执行流程,参数传递信息。只不过这三个日志级别,颗粒度大小不同,finest颗粒度高一些,日志就比较详细。这三个开发中我们拿其中一个就可以了。

设置日志级别:

all:日志的开关,每一个级别都有一个变量的取值
在这里插入图片描述
all的:整形的最小值。如果设置为all,那么上面所有级别都开启了
在这里插入图片描述
off:取的int类型的最大值。日志级别设置成off,上面所有的都比这个小,所有日志都不会进行记录。
在这里插入图片描述
设置成info,那么比info小的日志都不会输出,比info大的都会输出。

演示

在这里插入图片描述
输出结果:
在这里插入图片描述
所以,jul默认日志级别:info
在这里插入图片描述

自定义日志级别(硬编码)

我们想让上面案例所有级别都输出:

实现

系统应用时候是logger对象,但是真正工作的是处理器对象以及格式转换的fomatter对象。
所以现在想要实现自定义配置日志级别,要创建handler对象,现在期望输出的是控制台,所以创建ConsolHandler对象。
还需要创建简单的formatter格式转换对象。
在这里插入图片描述
然后需要让handler对象管理formatter,并且handler对象交给logger。
进行关联:
在这里插入图片描述
然后设置日志级别,要先把原有的日志级别关闭,在设置logger和处理器的日志级别。
在这里插入图片描述
然后同样输出七个日志级别:
在这里插入图片描述
观察控制台:所有级别都输出了
在这里插入图片描述

设置日志不输出到控制台,输出到磁盘文件

这里指定了日志记录器对象有两个处理器,一个是输出到控制台,一个是输出到我们指定的磁盘文件中
在这里插入图片描述
最终:控制台输出一份,指定的磁盘文件中输出一份
在这里插入图片描述
在这里插入图片描述

logger对象父子关系

父子关系是根据命名规范(类似于包结构),只要父包是包含子包这级目录的话,子包会默认继承父包;
在这里插入图片描述
如果没有定义父包,就默认继承RootLogger,有默认的处理器和格式转换器,级别是info,使用的是consuleHandler控制台输出,。
当logger2自定义完,并且关闭使用默认的处理器,logger1就默认使用logger2
在这里插入图片描述

案例说明:

在这里插入图片描述
输出结果:
在这里插入图片描述
logger2的父对象:
在我们没配置的情况下,默认是LogManager内部类的RootLogger对象。
名字:没有,就是一个空字符串""
在这里插入图片描述
所以,父对象没有指定的情况下,默认继承RootLogger,是logger处理器的顶级父对象,内部配置了向控制台输出的处理器以及简单的数据格式转换器

继承关系实现:

上面如果将logger2的日志级别设置为all(上面代码一样),logger1默认继承logger2,所以logger1的级别也是all。
!!但是注意:要让logger的默认配置脱离
在这里插入图片描述
在这里插入图片描述
再运行:
logger1输出了所有的级别:
在这里插入图片描述

JUL配置文件

上面都需要硬编码完成,不方便后期管理维护。
RootLogger对象默认加载用的就是配置文件的方式

看RootLogger对象:

ctrl键按住点击进入:
在这里插入图片描述
在这里插入图片描述
先创建了一个LogManager日志管理器对象,他是用于加载配置文件的,LogManager这个对象是一个单例对象,提供一个静态方法getLogManager()。
在这里插入图片描述
查看getLogManager():
在这里插入图片描述
在这里插入图片描述
这个方法里面:
这一行是加载配置文件,加载完配置文件就会去实例化rootLogger这个顶级父元素对象
在这里插入图片描述
点进去看如何加载配置文件的:
又是加载配置文件。
在这里插入图片描述
打上断点,运行一下程序:
到上面方法后,进入:
先去加载,当前系统下有没有一个配置类,我们并没有配置,这个方法我们不会进入。
在这里插入图片描述
继续往下,同样到一个当前系统下有没有自定义配置文件,我们也没有。
所以没有加载到,为null,读取java home也就是jdk安装的路径,找到jre环境,找到jre后,找到里面的lib目录,读取lib目录日志文件,日志文件名为:logging.properties
在这里插入图片描述
路径复制一下,在磁盘这个路径下找到这个配置文件:
在这里插入图片描述
在这里插入图片描述
打开:
handlers:默认的处理器对象:consoleHandlet
.level:因为顶级对象上面说了没有name,所以.级别是info

最下面两行console使用的级别:info;使用默认的数据转化器simpleFormatter

FileHandler对象参数:
pattern:指定日志文件输出的路径:%h当前用户文件名java开始,log结尾,%u以数字进行取值。
limit:当前文件最大存储多少条,默认值50000条
count:日志文件的数量,这里是10的时候,pattern%u会是0-9
formatter:底层用的是xmlfrmatter,xml是消息数据格式
在这里插入图片描述
把这个自带的配置文件复制到我们当前系统下:
在这里插入图片描述
在这里插入图片描述
然后先继续走代码:
跳出:
在这里插入图片描述
到:
配置文件读取完毕,就开始去初始化rootlogger对象,并且设置他的默认日志级别。
在这里插入图片描述

修改配置文件信息,设置日志级别

先把多余的内容删掉,我们修改成自己的配置:all
在这里插入图片描述
再写代码:
我们读取配置文件,从类路径去获取的话,通常用的是类加载器。
logmanagger提供了一个读取配置文件的方法:readConfiguration,需要一个流
在这里插入图片描述
运行结果:
在这里插入图片描述

filehandler对象(向文件输出)

在这里插入图片描述
做一个简单修改:
让在控制台,文件输出;
路径配置好;
文件输出是xml格式的
在这里插入图片描述
再运行程序:
在这里插入图片描述
控制台输出;
再去文件下看:
在这里插入图片描述
xml格式的日志文件:
在这里插入图片描述

配置文件详解

ConsoleHandler源码

有一个默认的配置信息,可以加载四个内容:
第一个是level;
第二个是filter过滤器我们暂时先不使用;
第三个是formatter;
第四个是encoding字符集。
在这里插入图片描述

如果是中文编码要指定下字符集。复制到配置文件里:(因为中文默认编码就是utf-8,所以之前都没有乱码)
在这里插入图片描述
运行即可:
在这里插入图片描述

SimpleFormatter(日志对象转换)源码

在这里插入图片描述
点进去:
在这里插入图片描述
获取系统默认配置加载这一组消息,指定输出消息的格式,我们可以手动做更改
在这里插入图片描述
手动更改:
将示例复制到配置文件中:
在这里插入图片描述
在这里插入图片描述
运行,再去看控制台:
在这里插入图片描述
格式不一样了:
在这里插入图片描述

FileHandler源码

在这里插入图片描述

上面配置是在文件里输出xml格式的,运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
xml格式不太好阅读,那就改为simpleformatter:
在这里插入图片描述
再运行:
在这里插入图片描述

上面案例发现的问题

新的内容会给旧的内容覆盖,这不是我们想要的,我们想要他也可以保留历史操作信息。五万条以后再去考虑覆盖的问题。
这时候就要去观察filehandler的属性是怎么设置的。

看源码:
append属性:决定是否以追加的方式添加日志记录,默认值为false。
在这里插入图片描述
所以我们把他改成true就可以了:
在这里插入图片描述
再去运行:
就会看见新内容没有覆盖旧的:
在这里插入图片描述

自定义logger使用

前面创建的logger对象默认使用的是rootlogger,rootlogger里面默认使用的规则是consule,我们给切换成了file。

现在自定义logger:
设置一个名称是itheima;
设置想输出的位置:控制台
设置自定义日志级别:我们现在设置成config用用(config要大写)
还要设置:要让他关闭默认的配置,这样就会走自己的不执行父类的
在这里插入图片描述
为了测试方便,在创建一个logger对象,这里就是”test“,他并没有遵循com.itheima自定义的,那么他就会默认使用root,也就是说把当前信息写入日志文件中而且是全部的信息。
在这里插入图片描述
运行,查看结果:
在这里插入图片描述
在这里插入图片描述

JUL执行原理和流程(debug查看源码)

我们需要关注两个对象:LogManager和Logger
我们需要知道这两个对象的执行流程和传递日志的信息。

1)首先web应用想进行日志记录的话,要调用Logger对象;
2)Logger对象初始化要调用LoggerManager对象:
1.他去加载项目下的配置文件或系统默认的配置文件;
2.初始化logger对象:rootLogger对象,和自定义的对象。交给LoggerManager。内部用的是一个loggerContains集合对象是一个map集合,key是logger的名称,value是当前对象的一个引用。
3) 用户就可以通过logger对象设置日志的级别以及具体的消息内容;
4)这里可以通过过滤器进行细粒度控制;
5)控制完放行交给handler对象决定日志输出的位置是控制台还是磁盘文件;
6)输出的消息内容通过formatter对象进行格式化;
7)最终输入指定的目标路径。
在这里插入图片描述

创建日志记录器源码

在这里插入图片描述
LogManager的初始化,需要加载的是配置文件,和初始化rootLogger对象。
下面是初始化我们自定义的对象。
在这里插入图片描述
先进上一行的:

初始化rootLogger对象

首先初始化logmanager对象,进入
在这里插入图片描述
进入:
里面做了一系列的判断
在这里插入图片描述
在下面这个断点这行加载配置文件,上面看过不再看了,
看下面一行:
实例化了一个rootlogger对象
在这里插入图片描述
owner就是logmanagger对象,对象的引用变量:
在这里插入图片描述
进入:
对象实例化的时候默认私有化了一个构造器,构造器内部调用了父类的方法(super),名称name就是一个空串。
他本身也是继承了Logger对象。
在这里插入图片描述

跳回来:
当我们这个新实例化对象创建成功以后,再继续往下执行:
add方法把根对象添加到logmanaggr对象里,进入
在这里插入图片描述

进入:
首先获取对象的名称,是一个空字符串。
下面LoggerContext对象,就是刚才所指的map集合
在这里插入图片描述
进入:
里面hashtable的map集合,名称叫namedloggers,里面key就是logger对象的名称,value就是logger对象的引用。
在这里插入图片描述
进入这个value的类,看看引用是什么东西:
里面有三个比较重要的属性:
第一个属性:是当前节点的名称
第二个属性:当前节点的对象
第三个属性:当前父节点对象的引用
我们会把每个logger对象生成一个节点对象叫logNode,具体怎么存储的,进入:
在这里插入图片描述

进入:
发现每个节点都有自己的子节点,这是一个hashmap,也就是说可以有多个子节点信息。
还有一个是当前节点的引用信息loggerRef;
还有当前节点的父引用信息parent;
还有loggerContext的引用信息

这里就可以存储一个logger对象的完整数据了。
在这里插入图片描述

再回到上面断点:
就把刚才的logger对象添加到context内部了:
在这里插入图片描述
继续往下执行:
添加完毕后,设置默认的logger日志级别:
在这里插入图片描述
进入:这里面有一个默认的叫global全局的, 是为了向上兼容1.7之前的日志系统,这里暂时不做讲解
在这里插入图片描述
往下拉:
代码继续往下执行的话就是一些添加,初始化的操作:
在这里插入图片描述

就可以跳出了:
在这里插入图片描述
到在这里,配置文件就已经成功的去加载了:
在这里插入图片描述
加载完也成功创建rootLogger对象了。

创建我们自己的对象

紧接着我们需要关注添加我们自己的对象了,就是com.itheima我们自定义的logger对象:
在这里插入图片描述
进入:
也是先判断这个方法的名称在logmanagger对象中存不存在
不存在,就会新建一个logger对象,名称就叫做com.itheima.

下面会触发一个addLogger方法,我们进入:
在这里插入图片描述
发现在里面又做一层判断,判断完没有问题的话,下面LoggerContext就又出来了:进入add方法:
在这里插入图片描述
进入:
在这里插入图片描述
继续进入:就是一些判断不用管继续执行
在这里插入图片描述
进入:
在这里插入图片描述
进入后:
在这里插入图片描述
往下拉:
最终在这里将我们当前对象的信息扔给了namedLoggers做了一个put
名称name是logger对象的全限定名,ref是当前对象的一个引用信息

下面设置了日志级别
在这里插入图片描述
往下拉,有个方法:
处理父对象的处理过程:
com.itheima有没有父对象呢,我们点击进入
在这里插入图片描述
进入后:
第一件事先判断了有没有关闭默认的配置信息".useParentHandlers",
如果关闭了就置为false
也就不会使用我们的consoleHandler处理器,也不会向控制台输出这些消息了。
在这里插入图片描述
往下拉:
上面那些判断完后,会判断自己有没有定义级别和处理器,或者说他自己自定义的父亲有没有进行定义:
这里做了一层for循环的执行流程
在这里插入图片描述

跳出来:
父亲添加完后,会添加一些节点信息:
在这里插入图片描述
往下拉:
显示:com.itheima的父就是rootlogger这个顶级父元素对象,看到了他们的关系:
在这里插入图片描述
往回跳:
这里就成功添加完毕了
在这里插入图片描述
继续跳:
添加完毕后:
下面一行代码非常重要:
com.itheima并没有指定handler处理器:
所以要使用rootlogger了,进入:
在这里插入图片描述
进入后:
com.itheima是他的名称,他会去查找有没有叫com.itheima.handlers这么一个自定义的处理器,因为我们上面已经给test的代码注释掉了,所以这里是拿不到的。
在这里插入图片描述
往下拉:
如果能拿到,就会使用handler具体执行输出的位置和消息的格式:
拿不到就使用rootlogger
在这里插入图片描述
然后直接放行就可以了,代码就看完了:
在这里插入图片描述
在这里插入图片描述

日志如何输出源码

进入:
在这里插入图片描述
进入后可以看见:
所有方法调用的都是通用的log方法,设置日志的级别和日志的消息:
在这里插入图片描述

进入:
这里做了一层判断:
点击下面的红色进入箭头跳转看下
在这里插入图片描述
跳转后:
这是一个日志参数的判断:
传递了当前的日志级别,如果当前的日志级别小于默认的日志级别,我们就不再输出,或者如果当前的日志级别等于最大值日志的开关,他也不再去输出。
显然我们的参数是不符合的,所以没有关系。
点击下面蓝色向上箭头跳出
在这里插入图片描述
返回true,就开始创建日志记录对象LogRecord,设置日志级别,
具体进行日志记录的话,会执行dolog方法,进入查看:
在这里插入图片描述
进入后;
做了一些代码的说明和判断,最终通过log方法执行的,进入:
在这里插入图片描述
里面做了一系列的判断,以及执行我们的过滤器
在这里插入图片描述
往下拉:
真正发布的是handler进行publish,发布我们的日志消息record,发现是用的logrecord:
在这里插入图片描述
进入:
默认调用了父类的方法:
在这里插入图片描述
进入:
里面执行了formatter简单类型转化器
在这里插入图片描述
往下拉:
进行了io流的输出:
在这里插入图片描述

继续跳出:
输出没问题的时候,会执行flush(),是刷新我们的io流,
放行到这里,看控制台,这时候并没有任何的日志消息:
在这里插入图片描述
执行左边的放行:
日志消息就有了,然后就会进入到第二个for循环,继续输出第二个日志消息
在这里插入图片描述
放行查看:第二个日志消息就输出了:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值