SpringBoot日誌實現

咖啡馬發表於2020-10-09

SpringBoot日誌實現

SpringBoot日誌預設實現

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-loggingLog4j , JUL(java.util.logging ) , Log4j2, Logback

JCL是Apache公司開發的一個框架,Jakarta小組開發的,Spring Framework在使用,但是2014年已經停止更新了。SLF4J , Log4j , Logback是同一個人寫的,這個人想優化Log4j,但是認為重新寫比較麻煩,於是寫了SLF4J這個抽象層日誌框架,又寫了Logback這個實現類。Log4j2也是Apache公司的,好多框架都沒適配。Hibernate底層使用Jboss-logging實現。

我們需要在左邊選一個門面(抽象層),右邊選一個實現。

Slf4j的使用

通過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的做法):

  1. 先排除掉其他日誌框架

  2. 然後用中間包來替換排除掉的日誌框架

  3. 最後再新增目標日誌框架

注意:在SpringBoot2.x版本的時候,上述的實現方式發生了一些改變,中間引入了"橋接"的概念,沒有直接通過模擬類名實現,比如類:SLF4JBridgeHandler,但是其底層的實現方法都是類似的,都是通過排除原有依賴實現,比如spring-boot-starter-logging的依賴:

JUL的橋接模式的實現是繼承JUL的Handler抽象類,按原始碼上的註釋所說,是實現一種redirected重定向。

<dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-to-slf4j</artifactId>
      <version>2.11.2</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jul-to-slf4j</artifactId>
      <version>1.7.26</version>
      <scope>compile</scope>
    </dependency>

注意實現由log4j-over-slf4j變成了log4j-to-slf4j

但是其底層依然不變,還是排除jar包,比如spring-boot底層引入的Apache的commons包:

<dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.5.0</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
        </exclusion>
      </exclusions>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.8</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
        </exclusion>
      </exclusions>
      <optional>true</optional>
    </dependency>

其中關於JCL日誌框架的處理是使用spring-jcl這個工程進行處理,整個spring-core都依賴於這個工程。

[外鏈圖片轉存失敗(img-O5dMxV5I-1566862162637)(/Users/circleus/Library/Application Support/typora-user-images/image-20190407221811598.png)]

SpringBoot引入新框架需注意

當SpringBoot引入新框架的時候,如果此框架使用了JUL,JCL,或者log4j,這個時候我們應該排除掉原來的日誌框架,避免因為現在SpringBoot中存在相同的日誌實現而造成jar包衝突衝突。

SpringBoot日誌配置

SpringBoot預設是info級別,如果沒有指定級別就使用 info 級別,這個預設級別也叫 root級別,想要調整某個包的日誌級別可以通過application.properties進行配置,例:

# com.anhe是我自己的包路徑
logging.level.com.anhe=trace

有時候想檢視Mybatis執行的具體sql語句可以將mapper對應的包路徑日誌級別設定為debug級別

logging.filelogging.pathExampleDescription
未配置未配置 只在控制檯輸出
指定檔名未配置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。

相關文章