本文共 4209 字,大约阅读时间需要 14 分钟。
在项目的开发中,日志是必不可少的一个记录事件的组件,所以也会相应的在项目中实现和构建我们所需要的日志框架。
而市面上常见的日志框架有很多,比如:JCL(Jakarta Commons Logging)、SLF4J、Jboss-logging、jUL(java.util.logging)、log4j、log4j2、logback等等,我们该如何选择呢?
通常情况下,日志是由一个抽象层+实现层的组合来搭建的。
而SpringBoot机智的选择了SLF4J+Logback的组合,这个组合是当下比较合适的一组(log4j2其实很厉害,但是太厉害还不能很好地整合)。SLF4J框架是一个常用的日志抽象层。
官网是最好的学习助手。 来到slf4j的官网的用户手册,我们可以在下边看到这张图: 首先SLF4J是一个日志门面,我们如果使用需要再另外找到一个日志实现框架,比如log4j、logback、log4j2、jcl、jul等等。并且slf4j和log4j以及logback是同一个人写的,先有的log4j,但是作者觉得这个框架功能并不是很理想,并且在log4j的基础上进行改进的话改进要很大,所以作者干脆一不做二不休又编写了另一个框架,也就是大名鼎鼎的Logback。
假如我们使用slf4j+logback,因为logback已经知道了slf4j的存在,所以可以完美搭配。但如果slf4j想要搭配其他框架的话,就要导入一个中间的过渡jar包,因为其他框架在编写之前并不知道slf4j的存在。
各种框架的过渡jar包如下所示:
这些jar包,往上实现了slf4j,往下内部又调用了log4j,jcl或者jul等等的方法,所以称之为过渡包。每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件
在我们的项目中,可能同时使用到了许多框架,比如spring、mybatis、hibernate等等。但是这些框架底层使用到了许多不同的日志框架,比如spring的默认日志框架是commens-logging。
不同的框架使用不同的日志框架,这样我们的项目看起来就像是一个日志的杂交系统。
那如何解决这种问题呢?
来看看slf4j的官网告诉我们如何使用吧:
slf4j官网的指示很明显,就是再用的时候需要导入一个“偷天换日包”。因为如果直接将这些框架所依赖的日志框架jar包排除出去,系统肯定会报错。我们就要使用一个偷天换日包,偷梁换柱包,比如:
拿spring举例子,因为spring必须使用commens-logging日志框架,而我们又想使用slf4j+logback的日志组合,那么我们必须要把commens-logging排除出去,但是怎么让系统不报错呢?我们使用这些偷天换日包的话,就像jcl-over-slf4j.jar。这个jar的名字很明显就是从JCL想slf4j转化,它内部包的包名,包括类名都和JCL的完全相同,但是这些类中的方法全部是调用的slf4j的方法进行实现,这样我们就可以完美实现slf4j+logback组合,并且令系统不报错。
这样spring依旧使用JCL作为日志支持,但是他所使用的JCL已经不是原来的JCL了,原来的JCL已经被我们排除出去,使用的是我们导入的偷天换日包,这样就不会报错了。
统一日志记录的思路(SpringBoot实现统一日志记录为slf4j的做法):
springboot使用的是***slf4j+logback***的组合。
按照以前的想法:
springboot的底层是spring,那么他必然依赖JCL,所以我们要先将原来的JCL排除出去,加入我们的偷天换日包。这个偷天换日包,包名和类名都是各种框架需要的包名和类名,以保证框架不会报错,但是底层实现都是通过slf4j的方法来实现的。这样就能实现slf4j+logback的组合了。但是在我使用springboot2.2.5版本的时候发现,框架组合并不是按照原来盗用原来日志框架的包名和类名来实现的,而是通过桥接方式实现,如下所示:
那么包名不是原来的包名的话,使用到jul的框架依旧会报错,点进这个类发现,虽然包名不是jul的包名,但是通过桥接模式依旧能让我们实现jul–>slf4j的改变。在springboot2.0之后:
在SpringBoot2.x版本的时候,上述的实现方式发生了一些改变,中间引入了"桥接"的概念,没有直接通过模拟类名实现,比如类:SLF4JBridgeHandler,但是其底层的实现方法都是类似的,都是通过排除原有依赖实现。
比如springboot2.2.5,快速创建一个springboot的web项目,进入pom文件:
打开项目的依赖图: 我们可以看到,jul-to-slf4j.jar和log4j-to-slf4j.jar等等这些jar包,这些包都是偷天换日包,内部调用的都是slf4j的方法但是包名和类名都不变,这样就可以很好地和slf4j整合在一起了。比如我们打开jul-to-slf4j.jar:
打开这个类,可以看到这个类的注释: 大概意思是:这个handler将会把JUL重定向(redirect)到slf4j,但是这个handler仅仅能将JUL桥接到slf4j。我觉得这种方式和原来的方式大同小异,都是排除原来依赖的日志jar包,然后导入一个过渡包,实现slf4j+JCL或者slf4j+JUL的整合。
SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可。
那我们在配置好日志之后,如何使用呢?
代码如下:Logger logger = LoggerFactory.getLogger(getClass());@Testpublic void contextLoads() { //日志的级别;//由低到高 trace
可以看到
输出只有info,warn和error级别。日志的默认级别是info(也就是root级别),只有info和高于info级别的日志才能输出。我们可以在配置文件application.properties中进行配置,如:
trace是最低级别,这样所有级别的日志信息都能输出出来。我们还可以配置哪些东西呢?
比如:logging.level.com.atguigu=trace#logging.path=# 不指定路径在当前项目下生成springboot.log日志# 可以指定完整的路径;#logging.file=G:/springboot.log# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件logging.path=/spring/log# 在控制台输出的日志的格式logging.pattern.console=%d{ yyyy‐MM‐dd} [%thread] %‐5level %logger{ 50} ‐ %msg%n# 指定文件中日志输出的格式logging.pattern.file=%d{ yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{ 50} ==== %msg%n像这样配置到application.properties这样,如果这样的话也太low了,我们可以写一个logback的专门的配置文件,那么这个配置文件放到哪里呢?
再次提到我觉得官网是最好的学习助手。
来到spring官网没查看springboot2.2.5的使用手册,在logging一栏:
所以我们可以把编写的logback.xml配置文件放到类路径的根目录下。这样springboot就可以自己帮我们加载进行配置了。还有在命名为logback.xml之外,还有一个logback-spring.xml,如果这样命名的话就可以使用spriingboot为我们提供的logback的额外功能,官网是这么说的如如下图所示:
点进去主要有两个扩展功能: 那为什么我们改个名字就可以使用springboot为我们提供的额外功能呢? 大概内容是这样的:因为标准的logback.xml文件会被日志框架过早的加载,所以你需要去使用logback-spring.xml或者定义一个logging.config。 这个拓展在logback的配置扫描下不能使用(logback-spring.xml会被spring扫描到),如果你非要这样使用,那么就会报这样一个错误。额外特性1:profile配置
大概意思就是,我们可以定义一个标签,里边有个name属性,我们在name属性中指定这个配置在哪个profile中生效,在其他profile不会生效。如下所示:%d{ yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level%logger{ 50} ‐ %msg%n %d{ yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level%logger{ 50} ‐ %msg%n
额外功能2:环境属性
可以使用标签,这个标签可以允许我们从application.yml中获取值,而并不是直接设一个值scope属性为该值使用的范围,source是获取值得来源,并使用${}的方式获该值。 使用方法如下所示:${ fluentHost} ...
转载地址:http://omqrn.baihongyu.com/