本篇主要介绍Spring Boot日志相关的内容
目录
[二、Spring Boot日志](#二、Spring Boot日志)
一、日志的定义和作用
什么是日志?日志记录了程序的具体的执行过程,就像我们平常写的日记,日记记录了我们每天都干了什么,而日志则记录了程序在什么时间执行了什么任务,发生了什么异常等等。总之,日志就是程序的日记,它记录了程序过往所执行的任务信息和数据。
日志有什么作用呢?日志的作用具体可以总结为下面四点:
- 系统监控:由于日志记录了程序的运行状态,因此我们可以统计出程序运行过程中的一些相关指标,比如响应量,响应时间,响应状态等,并为这些指标设置一个阈值,一旦这些指标超出这些阈值,就采取报警等措施。
- 数据收集,通过日志信息我们可以收集到一些用户数据,例如对某个资源的访问量,访问时长等等。收集到的这些数据可以应用到很多领域,比较常见的就是应用到推荐排序和数据统计。
- 审计,互联网不是法外之地,通过日志信息我们可以分析出用户是否有违反法律的行为,因为日志里面详细记录了用户的相关行为,如果数据被恶意修改或者获取,就可以快速通过日志定位到责任人。
- 定位bug,通过日志我们能清晰的看到程序执行过程中的问题,从而快速定位bug的产生原因,并及时解决,以此来加快开发效率。
二、Spring Boot日志
日志的使用
在Spring Boot中使用日志我们需要使用由orj.slf4j包提供的Logger类,具体使用方法如下:
创建Logger类(通过工厂类)
这个Class参数为当前类类型
打印日志:
控制台的打印结果:
可以发现我们刚才打印的日志已经按与系统相同的格式打印了。
日志框架
前面我们使用Logger类,是org.slf4j包下的,slf4j就是我们在这里使用的日志框架,但slf4j这个框架并没有真正去实现日志,实现日志是其他的日志框架,slfj相当于这些框架的"门面"。"门面"是门面模式这种设计模式的概念。
门面模式,又称外观模式,提供了一个统一接口,用来访问其子系统一些接口。这个统一的接口就是门面。
门面模式中包含两个角色:
- 门面角色(Facade):系统对外的统一接口
- 子系统角色(SubSystem):子系统通常有一个或者多个,里面包含了一个类的集合,这个集合具体完成了功能的实现。子系统并不知道门面的存在,门面对于子系统而言就是一个来访问的客户端,也就是说门面对于子系统是透明的。
门面就好比我们去买车时接待我们的接待员,我们只需要与接待员沟通买车的需求和个人信息,至于买车的一些具体程序都由接待员来替我们执行。
下面我们通过一个基于门面模式设计的代码来更深刻的体会一下:
我们定义一个灯接口,里面包含两个方法 ,关灯,开灯:
然后我们来定义厨房,餐厅,卧室这几个子系统:
创建门面
通过上述代码我们可以发现,如果我们要关闭所有灯,只需要创建门面即可,而不需要再一个一个去创建子系统。由此可以总结出门面模式的下述优点:
- 客户端与子系统的耦合程度低,无论子系统怎么变化,客户端都是无需感知的。
- 降低了子系统的使用难度,客户端并不需要关心子系统的具体实现与使用,只需要与门面交互就能实现需求
- 提升了安全性,可以在门面中设置安全权限,没有权限就无法访问。
具体实现了日志的框架有很多,例如log4j,logback等,不同组件和依赖使用的日志框架可能会存在差异,因此我们的项目中可能会同时出现多个日志框架,这会给我们带来很多问题:
- 当项目中存在多个日志框架时,由于不同的日志框架的配置和api有所不同,这就导致我们不得不维护多套日志框架的配置文件,十分麻烦。
- 当我们要修改项目中的日志框架时,需要跟据新的日志框架进行代码修改,从而增加工作量。
因此我们十分需要引入slf4j作为各种日志实现框架的门面,通过slf4j,就使得我们的项目与各日志实现框架有了一个统一API,并且我们只需要维护一套配置文件,不再需要每个日志框架都维护一个配置文件,而且当我们更换日志框架时,也不需要再修改代码了。
日志级别
日志针对不同的日志信息进行了分级,每一级都代表着日志对应问题的严重程度,严重程度从高到低依次为:FATAL,ERROR,WARN,INFO,DEBUG,TRACE,具体含义如下:
- FATAL:致命信息,表示要立即处理的系统级错误
- ERROR:错误信息,级别较高的错误日志信息,但不影响系统的继续执行
- WARN:警告信息,不影响使用,但需要注意的问题
- INFO:普通信息,记录了系统正常执行时的一些信息,例如系统启动完成,系统启动完成等,Spring Boot的默认日志级别
- DEBUG:调试信息,打印调试时需要的信息
- TRACE:比调试信息粒度更细的日志信息,除非要特殊事件需要使用,否则请用DEBUG级别代替
通过Logger我们可以打印出不同日志级别的信息,具体如下:
执行结果:
可以发现除了DEBUG级别的,其他级别的日志信息打印了,之所以没有打印DEBUG级别的,是因为控制台只会打印当前项目设置的日志级别和级别更高的日志信息,而系统默认使用INFO日志级别,所以没有打印级别较低的DEBUG。要打印DEBUG需要修改日志级别,系统的日志级别可以在配置文件中进行配置,具体配置如下:
修改日志级别后,可以发现DEBUG一级打印出来了,并且还多了很多其他内容,这是因为整个系统的日志级别都已经改为DEBUG了,所以项目启动的一些DEBUG级别的日志信息也打印出来了。
TRACE和FATAL这两种日志级别我们不能再配置文件中配置,毕竟系统崩溃了我们压根就不需要看日志信息就能知道,而且我们也不需要精细到每执行一步都打印一个日志信息。
日志持久化
前面我们说过日志有数据收集等作用,因此我们需要将日志信息进行一个持久化处理,也就是保存在文件里,以便于以后的分析和使用。将日志存到文件需要在配置文件里配置两个配置信息:
- logging.file.path : 存放日志的文件的位置
- logging.file.name:存放日志文件的文件名称
(如果这个文件在项目目录下,我们只需要配置name,并且在name中设置路径和文件名,如果不在项目路径中我们只需要设置path,文件名默认只能为spring.log)
接下来,我们创建一个包log来保存存放日志的文件,然后再配置一下配置项:
执行代码后可以发现日志信息已经存储到文件里了。
日志文件分割
如果我们在一个文件里存储了过多的日志信息,不仅查起来麻烦,而且打开也会十分耗时,因此我们需要对日志文件进行分割,系统默认日志文件超过10m自动分割,但我们也可以自己进行配置,配置项如下:
logging.logback.rollingpolicy.file-name-pattern:配置分割后的文件名,默认为${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz。LOG_FILE为原始文件名
logging.logback.rollingpolicy.max-file-size:配置文件最大大小,达到这个大小自动分割,默认为10m。
接下来我们来配置一下这两个配置项
执行后可以发现日志文件自动分割成了多个
日志格式
通过前面的日志信息我们可以发现日志的格式都是一样的,因为这里都是以系统默认的日志格式进行打印,系统的日志格式我们可以自己配置,相关的配置项有:
- logging.pattern.consle:控制台输出的日志信息的格式,默认为%clr(%d{{LOG_DATEFORMAT_PATTERN:-yyyy-MMdd'T'HH:mm:ss.SSSXXX}}){faint} %clr({LOG_LEVEL_PATTERN:- %5p})%clr({PID:-}){magenta}%clr(---){faint}%clr(\[%15.15t\]) {faint}%clr(%-40.40logger{39}){cyan}%clr(:){faint} %m%n{LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
- logging.pattern.file:日志文件保存的日志信息的格式,默认为:%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MMdd'T'HH:mm:ss.SSSXXX}} {LOG_LEVEL_PATTERN:-%5p}{PID:-} ---[%t]%-40.40logger{39}: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
这里的符号的具体含义大家可以去下面的链接查询,里面还有一些日志其他的相关配置:
https://logback.qos.ch/manual/layouts.html#conversionWord
更方便的打印日志
最后再分享一个更方便的使用日志的方式,前面我们要使用日志都得自己创建一个logger类,非常麻烦,使用lombok提供的@Slf4j就不需要自己创建了,他会自动在加了这个注解的类中,生成一个Logger对象,对象名为log,我们直接使用就行。
在@Slf4j的实现我们可以发现,@Retention(标注注解的生命周期)的参数为source
由此可以知道,这个@Slf4j只存在于源码阶段,源码编译后就消失了,我们通过target中编译后的代码来看一下
可以发现,编译后的代码中果然没有@Slf4j了,取而代之的是在mian方法中增加了我们原来 创建Logger的代码,并且将我们前面的log改为这里的创建的Logger对象名.这也就解释了我们为什么没创建Logger也能打印日志了,全是得益于@Slf4j在发挥作用。