( 十三 ) SpringBoot 【日志一】統一日志框架
1、簡介
在項目開發中,日志十分的重要,不管是記錄運行情況還是定位線上問題,都離不開對日志的分析。在 Java 領域里存在着多種日志框架,如 JCL、SLF4J、Jboss-logging、jUL、log4j、log4j2、logback 等等。
2、日志框架的選擇
市面上常見的日志框架有很多,它們可以被分為兩類:日志門面(日志抽象層)和 日志實現,如下表:
日志分類 | 描述 | 舉例 |
---|---|---|
日志門面(日志抽象層) | 為 Java 日志訪問提供一套標准和規范的 API 框架,其主要意義在於提供接口。 | JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging |
日志實現 | 日志門面的具體的實現 | Log4j、JUL(java.util.logging)、Log4j2、Logback |
通常情況下,日志由一個日志門面與一個日志實現組合搭建而成,Spring Boot 選用 SLF4J + Logback 的組合來搭建日志系統。
SLF4J 是目前市面上最流行的日志門面,使用 Slf4j 可以很靈活的使用占位符進行參數占位,簡化代碼,擁有更好的可讀性。
Logback 是 Slf4j 的原生實現框架,它與 Log4j 出自一個人之手,但擁有比 log4j 更多的優點、特性和更做強的性能,現在基本都用來代替 log4j 成為主流。
3、SLF4J 的使用
在項目開發中,記錄日志時不應該直接調用日志實現層的方法,而應該調用日志門面(日志抽象層)的方法。
在使用 SLF4J 記錄日志時,我們需要在應用中導入 SLF4J 及日志實現,並在記錄日志時調用 SLF4J 的方法,例如:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HelloWorld { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(HelloWorld.class); //調用 sl4j 的 info() 方法,而非調用 logback 的方法
logger.info("Hello World"); } }
SLF4J 作為一款優秀的日志門面或者日志抽象層,它可以與各種日志實現框架組合使用,以達到記錄日志的目的,如下圖(參考自 SLF4J 官方)
從 SLF4J 官方給出的方案可以看出:
- Logback 作為 Slf4j 的原生實現框架,當應用使用 SLF4J+Logback 的組合記錄日志時,只需要引入 SLF4J 和 Logback 的 Jar 包即可;
- Log4j 雖然與 Logback 出自同一個人之手,但是 Log4j 出現要早於 SLF4J,因而 Log4j 沒有直接實現 SLF4J,當應用使用 SLF4J+Log4j 的組合記錄日志時,不但需要引入 SLF4J 和 Log4j 的 Jar 包,還必須引入它們之間的適配層(Adaptation layer)slf4j-log4j12.jar,該適配層可謂“上有老下有小”,它既要實現 SLF4J 的方法,還有調用 Log4j 的方法,以達到承上啟下的作用;
- 當應用使用 SLF4J+JUL 記錄日志時,與 SLF4J+Log4j 一樣,不但需要引入 SLF4J 和 JUL 的對應的 Jar 包,還要引入適配層 slf4j-jdk14.jar。
這里我們需要注意一點,每一個日志的實現框架都有自己的配置文件。使用 slf4j 記錄日志時,配置文件應該使用日志實現框架(例如 logback、log4j 和 JUL 等等)自己本身的配置文件進行配置。
4、統一日志框架(通用)
通常一個完整的應用下會依賴於多種不同的框架,而且它們記錄日志使用的日志框架也不盡相同,例如,Spring Boot(slf4j+logback),Spring(commons-logging)、Hibernate(jboss-logging)等等。那么如何統一日志框架的使用呢?
對此,SLF4J 官方也給出了相應的解決方案,如下圖:
從上圖中可以看出,統一日志框架一共需要以下 3 步 :
- 排除應用中的原來的日志框架;
- 引入替換包替換被排除的日志框架;
- 導入 SLF4J 實現。
SLF4J 官方給出的統一日志框架的方案是“狸貓換太子”,即使用一個替換包來替換原來的日志框架,例如 log4j-over-slf4j 替換 Log4j(Commons Logging API)、jul-to-slf4j.jar 替換 JUL(java.util.logging API)等等。
替換包內包含被替換的日志框架中的所有類,這樣就可以保證應用不會報錯,但替換包內部實際使用的是 SLF4J API,以達到統一日主框架的目的。
5、SpringBoot 中 統一日志框架
我們在使用 Spring Boot 時,同樣可能用到其他的框架,例如 Mybatis、Spring MVC、 Hibernate 等等,這些框架的底層都有自己的日志框架,此時我們也需要對日志框架進行統一。
我們知道,統一日志框架的使用一共分為 3 步,Spring Boot 作為一款優秀的開箱即用的框架,已經為用戶完成了其中 2 步:引入替換包 和 導入 SLF4J 實現。
Spring Boot 的核心啟動器 spring-boot-starter 引入了 spring-boot-starter-logging,使用 IDEA 查看其依賴關系,如下圖:
從圖 3 可知,spring-boot-starter-logging 的 Maven 依賴不但引入了 logback-classic (包含了日志框架 SLF4J 的實現),還引入了 log4j-to-slf4j(log4j 的替換包),jul-to-slf4j (JUL 的替換包),即 Spring Boot 已經為我們完成了統一日志框架的 3 個步驟中的 2 步。
SpringBoot 底層使用 slf4j+logback 的方式記錄日志,當我們引入了依賴了其他日志框架的第三方框架(例如 Hibernate)時,只需要把這個框架所依賴的日志框架排除,即可實現日志框架的統一。
示例代碼如下:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-console</artifactId>
<version>${activemq.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>