1. 日志框架
目前市场上存在非常多的日志框架,比如 JUL(java.util.logging),JCL(Apache Commons Logging),Log4j,Log4j2,Logback、SLF4j、jboss-logging 等。
由于日志框架繁多复杂,所以除了日志的具体实现框架之外,另外还定义了相关的门面框架,也就是具体实现框架的抽象框架。门面框架定义了一套统一的接口,用户可以更为方便的去使用不同的实现框架。下面是其对应的关系:
日志门面框架 | 日志实现框架 |
---|---|
Log4j JUL(java.util.logging) Log4j2 Logback |
对于日志门面框架,我们推荐使用 SLF4J,而日志实现框架则推荐使用 Logback,它是 Log4j 的新版本。另外 SpringBoot 底层选用的也是 SLF4j 和 Logback 这两个框架。
2. SLF4j 使用
对于 SLF4j 的使用,我们可以参考其官方文档,下面我们就结合着官方文档来介绍一下 SLF4j 的使用吧。
在开发的时候,日志记录方法的调用,不应该来直接调用日志的具体实现类的方法,而是调用日志抽象层类里面的方法。比如下面的示例,我们在导入 SLF4j 和 Logback 的 jar 之后,我们应该直接调用日志抽象层类(即 SLF4j)的方法来使用日志框架。
1 | import org.slf4j.Logger; |
下图是官网给出了一个图例,该图介绍了 SLF4j 与具体的日志实现框架,比如 Logback、Log4j 或者 JUL 之间进行绑定时底层具体的 jar 之间的具体关系。比如 SLF4j 与 Logback 之间进行绑定时,需要 slf4j-api.jar 和 logback-classic.jar 及 logback-core.jar。
当 SLF4j 与 Log4j 进行绑定时,因为 log4j.jar 的出现比 slf4j.jar 的出现要早的多。为了使两者能够相互适配,需在中间多加一个适配层的 slf4j-log412.jar。
需要说明的一点是,每一个日志的实现框架都有自己的配置文件。使用 slf4j 以后,配置文件还是做成其日志实现框架自己本身的配置文件。
在实际的开发中,我们有时候会遇到日志框架冲突的情况。比如现在我们有一个 SpringBoot 应用,并且该应用整合了其他含有 commons-logging 日志框架的框架。由于 SpringBoot 自身使用的日志实现框架是 Logback,其会与 commons-logging 日志框架发生冲突。那么如何统一日志框架,避免出现日志框架冲突的情况呢?我们先来查看 slf4j 给出的图例:
查看上图左上角的示例,当使用 SLF4j 与 Logback 进行绑定时,此时当前应用可能存在其他日志实现框架 commons-logging,为了避免 commons-logging 与 Logback 冲突,可以使用 jcl-over-slf4j.jar 将 commons-logging 替代
掉,其作用相当于替换了 commons-logging 这个日志框架。
最后,我们还需要在配置文件中使用 <exclusions> 将 commons-logging 排除掉,这样才能真正的避免日志框架冲突问题。
3. SpringBoot 日志关系
查看 SpringBoot 的 pom 配置文件,我们可以发现 SpringBoot 是使用如下依赖来做日志功能的:
1 | <dependency> |
我们可以在 pom 文件右键点击 Show Dependencies,如下图所示:
点击后,我们可以以下图的形式查看 SpringBoot 中各个依赖之间的关系。观察下图,我们可以发现 logback 和 slf4j 作为其日志框架,并且使用了如 log4j-to-slf4j 等中间 jar 排除了 log4j 等日志框架,避免日志框架冲突的情况。
当我们要整合其他框架且出现日志冲突时,我们在引入该框架的依赖时可以使用 exclusions 标签来排除该框架所引用的日志框架。比如早期的 Spring 使用的是 commons-logging 日志框架,所以 SpringBoot 1.x 在整合早期的 Spring 时不得不排除掉 commons-logging,代码示例如下:
1 | <dependency> |
SpringBoot 能自动适配所有的日志,而且底层使用 slf4j+logback 的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可。
4. 日志使用
4.1 默认配置
SpringBoot 本身默认帮我们配置好了日志,我们可以使用单元测试进行校验:
1 | import org.junit.jupiter.api.Test; |
需要注意的是,日志级别由低到高分别为 trace < debug < info < warn < error。其中 SpringBoot 的默认日志输出级别是 info,所以上述的代码的单元测试仅输出 info 级别及以上的信息。具体输出结果如下所示:
1 | 2019-11-30 16:29:22.584 INFO 8928 --- [ main] c.s.Springboot03LoggingApplicationTests : 这是 info 日志 |
4.1.1 日志级别
由于 SpringBoot 的默认日志输出级别是 info,我们也可以修改器默认配置。我们可以在 application.properties 中进行如下配置:
1 | logging.level.com.shoto=trace |
其中 com.shoto 为当前的项目 main/java 下的包名,也就是说以上方法仅适用于程序包级别的日志记录。
4.1.2 日志文件输出
默认情况下,Spring Boot 仅将记录输出到控制台,不写到日志文件中。如果除了控制台输出外还想写日志文件,则需要设置一个logging.file.name
或logging.file.path
属性(例如,在中application.properties
)。
下表描述了logging.file.name
或logging.file.path
两者之间的区别,具体如下:
logging.file.name | logging.file.path | 例子 | 描述 |
---|---|---|---|
(未指定) | (未指定) | 仅控制台记录输出。 | |
特定日志文件 | (未指定) | my.log | 写入指定的日志文件。名称可以是确切位置,也可以是相对于当前目录的位置。 |
(未指定) | 具体目录 | /var/log | 写入spring.log 指定的目录。名称可以是确切位置,也可以是相对于当前目录的位置。 |
配置文件示例如下所示:
1 | # 将日志记录到当前项目路径下的my.log中 |
4.1.3 输出格式
SpringBoot 的默认日志输出格式如下所示:
1 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n |
具体参数说明如下:
1 | %d表示日期时间, |
输出示例:
1 | 2019-11-30 16:29:22.584 INFO 8928 --- [ main] c.s.Springboot03LoggingApplicationTests : 这是 info 日志 |
当然,我们也可以修改日志输出格式,比如在 application.properties 中进行如下配置:
1 | # 在控制台输出的日志的格式 |
4.2 自定义配置
我们可以还通过在类路径的根目录下添加适当的配置文件来进一步自定义各种日志记录,这样 SpringBoot 就不需要使用其本身的默认配置了。根据不同的日志记录系统,将加载以下名称的文件:
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
比如对于 Logback 日志框架,我们在类路径直接编写 logback.xml 文件就可以被日志框架自动识别出来了;而对于 logback-spring.xml 这些带 -spring 的日志配置文件(推荐使用),则不直接由日志框架去加载日志的配置内容,而是由 SpringBoot 去解析日志配置。
带 -spring 的日志配置文件可以使用 SpringBoot 的高级Profile功能(根据不同环境(如开发环境或生产环境)使用不同的日志配置),因此只能由 SpringBoot 去解析日志配置。
4.2.1 示例1
我们在类路径 resource 下添加 logback.xml 日志配置文件,具体配置如下所示。可以自行运行测试一下控制台和日志文件的输出。日志框架会自动识别该文件的内容。
1 |
|
4.2.2 示例2
我们在类路径 resource 下修改 logback.xml 为 logback-spring.xml 日志配置文件。与 logback.xml 配置的不同仅仅在于控制台日志输出格式的配置上:
1 | <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --> |
然后在 application.properties 中配置如下内容来激活开发环境,如下所示:
1 | spring.profiles.active=dev |
单元测试在控制台输出日志记录后,其输出格式便是符合这种 %d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n
格式的。
5. 日志框架切换
为了演示日志框架的切换,我们可以将 SpringBoot 的日志框架 Logback 替换成 Log4j(当然实际情况是不推荐的,因为Log4j 不是个很好的日志框架)。
我们修改 pom 文件,首先排除掉 Logback 相关的依赖,然后在导入 slf4j 与 log4j 之间适配层的依赖。由于 SpringBoot 本身已有 Log4j 的依赖,所以这里并不要导入该依赖。
1 | <dependency> |
当然,我们也可以将 SpringBoot 的日志框架 Logback 替换成 Log4j2,以下是 pom 文件中的相关配置:
1 | <dependency> |
因为 spring-boot-starter-logging 中的 log4j-to-slf4j 不能与 Log4j2 中的 log4j-slf4j-impl 一起出现,所以这里我们一并将 spring-boot-starter-logging 排除掉了。