SpringBoot默认的日志实现是使用slf4j
+logback
,这种实现类似于JDBC + 数据库驱动(统一接口+实现类)。
slf4j叫做日志门面,是一个统一的日志接口层,各种具体的日志实现都可以通过slf4j来实现,比如logback就是一个具体的日志门面的实现。
市面上常见的日志框架有:JUL , JCL , Jboss-logging , logback , log4j , log4j2 , slf4j等等,他们的分类如下:
日志门面(日志的抽象层) | 日志实现 |
---|---|
JCL(Jakarta Commons Logging) , SLF4J(Simple Logging Facade for Java), Jboss-logging | Log4j , JUL(java.util.logging ) , Log4j2, Logback |
JCL是Apache公司开发的一个框架,Jakarta小组开发的,Spring Framework在使用,但是2014年已经停止更新了。SLF4J , Log4j , Logback是同一个人写的,这个人想优化Log4j,但是认为重新写比较麻烦,于是写了SLF4J这个抽象层日志框架,又写了Logback这个实现类。Log4j2也是Apache公司的,好多框架都没适配。Hibernate底层使用Jboss-logging实现。
我们需要在左边选一个门面(抽象层),右边选一个实现。
通过Slf4j的LoggerFactory
创建Logger
来进行日志的记录;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
slf4j官网:https://www.slf4j.org/
下图是使用slf4j如何实现各种日志框架:
可以看到,只引入slf4j是不能够实现日志记录的,在引入slf4j-api.jar的基础上;
如果要实现logback日志框架,需要引入logback-core.jar和logback-classic.jar;
如果要实现log4j日志框架,需要引入slf4j-log412.jar(log4j适配slf4j的jar),log4j.jar。其他情况类似。
**每一个日志实现框架都有自己的配置文件,使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件。**比如实现框架选用logback,那么配置文件就写logback.xml这种,实现框架选log4j,那么配置问价就选log4j.xml这种。
但是在实际项目中,我们所引入的不同框架的底层日志框架是不一样的。比如:
Spring使用JCL,Hibernate使用Jboss等等,我们就需要统一日志记录,让不同的框架统一使用slf4j进行输出,这样我们就不用写别的配置文件,统一使用logback进行配置。具体做法如下图:
如上图,比如Spring框架,为了达到上述目标,我们需要排除掉Spring底层的commons-logging包,(不引入Spring会报包找不到的错误)然后引入包装层jcl-over-slf4j,这个包装层jar的包路径,类名等都采用commons-logging的形式进行配置,但是底层实现是slf4j,最后添加logback的jar包。
统一日志记录的思路(SpringBoot实现统一日志记录为slf4j的做法):
先排除掉其他日志框架
然后用中间包来替换排除掉的日志框架
最后再添加目标日志框架
注意:在SpringBoot2.x版本的时候,上述的实现方式发生了一些改变,中间引入了"桥接"的概念,没有直接通过模拟类名实现,比如类:
SLF4JBridgeHandler
,但是其底层的实现方法都是类似的,都是通过排除原有依赖实现,比如spring-boot-starter-logging的依赖:
JUL的桥接模式的实现是继承JUL的Handler抽象类,按源码上的注释所说,是实现一种redirected重定向。
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-to-slf4jartifactId>
<version>2.11.2version>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jul-to-slf4jartifactId>
<version>1.7.26version>
<scope>compilescope>
dependency>
注意实现由log4j-over-slf4j变成了log4j-to-slf4j
但是其底层依然不变,还是排除jar包,比如spring-boot底层引入的Apache的commons包:
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-dbcp2artifactId>
<version>2.5.0version>
<scope>compilescope>
<exclusions>
<exclusion>
<artifactId>commons-loggingartifactId>
<groupId>commons-logginggroupId>
exclusion>
exclusions>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.8version>
<scope>compilescope>
<exclusions>
<exclusion>
<artifactId>commons-loggingartifactId>
<groupId>commons-logginggroupId>
exclusion>
exclusions>
<optional>trueoptional>
dependency>
其中关于JCL日志框架的处理是使用spring-jcl这个工程进行处理,整个spring-core都依赖于这个工程。
[外链图片转存失败(img-O5dMxV5I-1566862162637)(/Users/circleus/Library/Application Support/typora-user-images/image-20190407221811598.png)]
当SpringBoot引入新框架的时候,如果此框架使用了JUL,JCL,或者log4j,这个时候我们应该排除掉原来的日志框架,避免因为现在SpringBoot中存在相同的日志实现而造成jar包冲突冲突。
SpringBoot默认是info级别,如果没有指定级别就使用 info 级别,这个默认级别也叫 root级别,想要调整某个包的日志级别可以通过application.properties进行配置,例:
# com.anhe是我自己的包路径
logging.level.com.anhe=trace
有时候想查看Mybatis执行的具体sql语句可以将mapper对应的包路径日志级别设置为debug级别。
logging.file | logging.path | Example | Description |
---|---|---|---|
未配置 | 未配置 | 只在控制台输出 | |
指定文件名 | 未配置 | my.log | 输出日志到my.log文件 |
未配置 | 指定目录 | /var/log | 输出到指定目录的spring.log文件中 |
指定文件名 | 指定目录 | /Users/circleus/Documents/tmp /Users/circleus/Documents/my.log |
都指定的时候以logging.file为准 |
# 配置在指定目录,不指定路径的时候就是配置在项目路径下
logging.file=/Users/circleus/Documents/my.log
# 在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
# 在文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
此路径配置的xml配置了项目关于日志的默认配置:spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE.jar!/org/springframework/boot/logging/logback/defaults.xml
除此之外,还可以配置日志滚动条件:比如配置日志文件满10M就记录到下一个文件,文件名以i递增,或者按天进行滚动。日志配置文件的名称:logback-spring.xml
或者logback.xml
,推荐使用logback-spring.xml
,因为配置成logback-spring.xml
是由SpringBoot自己加载,不是由日志框架直接加载,可以使用高级特性:,通过这个特性,可以配置不同环境配置不同的日志级别,比如开发环境使用debug,生产环境使用info。