天天看點

SpringBoot學習-(十)SpringBoot日志處理

預設日志Logback

SLF4J——Simple Logging Facade For Java,它是一個針對于各類Java日志架構的統一Facade抽象。Java日志架構衆多——常用的有java.util.logging, log4j, logback,commons-logging, Spring架構使用的是Jakarta Commons Logging API (JCL)。而SLF4J定義了統一的日志抽象接口,而真正的日志實作則是在運作時決定的——它提供了各類日志架構的binding。

Logback是log4j架構的作者開發的新一代日志架構,它效率更高、能夠适應諸多的運作環境,同時天然支援SLF4J。

預設情況下,Spring Boot會用Logback來記錄日志,并用INFO級别輸出到控制台。在運作應用程式和其他例子時,你應該已經看到很多INFO級别的日志了。

SpringBoot學習-(十)SpringBoot日志處理

從上圖可以看到,日志輸出内容元素具體如下:

  • 時間日期:精确到毫秒
  • 日志級别:ERROR, WARN, INFO, DEBUG or TRACE
  • 程序ID
  • 分隔符:— 辨別實際日志的開始
  • 線程名:方括号括起來(可能會截斷控制台輸出)
  • Logger名:通常使用源代碼的類名
  • 日志内容

添加日志依賴

假如maven依賴中添加了spring-boot-starter-logging:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>      

那麼,我們的Spring Boot應用将自動使用logback作為應用日志架構,Spring Boot啟動的時候,由org.springframework.boot.logging.Logging-Application-Listener根據情況初始化并使用。

但是呢,實際開發中我們不需要直接添加該依賴,你會發現spring-boot-starter其中包含了 spring-boot-starter-logging,該依賴内容就是 Spring Boot 預設的日志架構 logback。

SpringBoot學習-(十)SpringBoot日志處理

預設配置屬性支援

Spring Boot為我們提供了很多預設的日志配置,是以,隻要将spring-boot-starter-logging作為依賴加入到目前應用的classpath,則“開箱即用”。

下面介紹幾種在application.yml就可以配置的日志相關屬性。

控制台輸出

日志級别從低到高分為TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果設定為WARN,則低于WARN的資訊都不會輸出。

Spring Boot中預設配置ERROR、WARN和INFO級别的日志輸出到控制台。

在application.yml中配置debug=true,該屬性置為true的時候,核心Logger(包含嵌入式容器、hibernate、spring)會輸出更多内容,但是你自己應用的日志并不會輸出為DEBUG級别

# 日志配置
debug: true      

檔案輸出

預設情況下,Spring Boot将日志輸出到控制台,不會寫到日志檔案。如果要編寫除控制台輸出之外的日志檔案,則需在application.yml中設定logging.file或logging.path屬性。

  • logging.file,設定檔案,可以是絕對路徑,也可以是相對路徑。如:logging.file=AhutOne.log
  • logging.path,設定目錄,會在該目錄下建立spring.log檔案,并寫入日志内容,如:logging.path=/log/myLog

如果隻配置 logging.file,會在項目的目前路徑下生成一個 xxx.log 日志檔案。

# 日志配置
logging:
  file: log/AhutOne.log      
SpringBoot學習-(十)SpringBoot日志處理
SpringBoot學習-(十)SpringBoot日志處理

如果隻配置 logging.path,在 /log/myLog檔案夾生成一個日志檔案為 spring.log

# 日志配置
logging:
  path: log/myLog      
SpringBoot學習-(十)SpringBoot日志處理
SpringBoot學習-(十)SpringBoot日志處理
SpringBoot學習-(十)SpringBoot日志處理

注:二者不能同時使用,如若同時使用,則隻有logging.file生效

預設情況下,日志檔案的大小達到10MB時會切分一次,産生新的日志檔案,預設級别為:ERROR、WARN、INFO

級别控制

所有支援的日志記錄系統都可以在Spring環境中設定記錄級别(例如在application.yml中)

格式為:’logging.level.* = LEVEL’

  • logging.level:日志級别控制字首,*為包名或Logger名
  • LEVEL:選項TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF

舉例:

# 日志配置
logging:
  level:
    # com.ahut包下所有class以DEBUG級别輸出
    com.ahut: DEBUG
    # root日志以WARN級别輸出      

自定義日志配置

由于日志服務一般都在ApplicationContext建立前就初始化了,它并不是必須通過Spring的配置檔案控制。是以通過系統屬性和傳統的Spring Boot外部配置檔案依然可以很好的支援日志控制和管理。

根據不同的日志系統,你可以按如下規則組織配置檔案名,就能被正确加載:

  • Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  • Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  • Log4j2:log4j2-spring.xml, log4j2.xml
  • JDK (Java Util Logging):logging.properties

Spring Boot官方推薦優先使用帶有-spring的檔案名作為你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名為logback-spring.xml的日志配置檔案,spring boot可以為它添加一些spring boot特有的配置項(下面會提到)。

上面是預設的命名規則,并且放在src/main/resources下面即可。

如果你即想完全掌控日志配置,但又不想用logback.xml作為Logback配置的名字,可以通過logging.config屬性指定自定義的名字:

# 日志配置
logging:
  config: classpath:logging-config.xml      

雖然一般并不需要改變配置檔案的名字,但是如果你想針對不同運作時Profile使用不同的日志配置,這個功能會很有用。

下面我們來看看一個普通的logback-spring.xml例子

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>
    <property name="log.path" value=".\\test\\log\\"
    <property name="log.file" value=".\\test\\logback.log"
    <!--輸出到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> 
            </filter> -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--輸出到檔案 -->
    <appender name="file"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.file}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}logback.%d{yyyy-MM-dd_HH-mm}.log
            </fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console"
        <appender-ref ref="file"
    </root>

    <!-- 列印執行的sql name指定mapper所在的包,additivity設定為true時,父級也會列印相應的資訊,相當于列印多次 -->
    <logger name="com.ahut.mapper" level="DEBUG" additivity="false">
        <appender-ref ref="console"
        <appender-ref ref="file"
    </logger>

    <!-- logback為java中的包 -->
    <!--<logger name="com.dudu.controller"/> -->
    <!--logback.LogbackDemo:類的全路徑 -->
    <!--<logger name="com.dudu.controller.LearnController" level="WARN" additivity="true"> -->
    <!--<appender-ref ref="console"/> -->
    <!--</logger> -->

    <!-- 測試環境+開發環境. 多個使用逗号隔開. -->
    <springProfile name="test,dev">
        <logger name="com.ahut.action" level="info"
    </springProfile>
    <!-- 生産環境. -->
    <springProfile name="prod">
        <logger name="com.ahut.action" level="ERROR"
    </springProfile>

</configuration>      

根節點​

​<configuration>​

​包含的屬性

  • scan:當此屬性設定為true時,配置檔案如果發生改變,将會被重新加載,預設值為true。
  • scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間機關,預設機關是毫秒。當scan為true時,此屬性生效。預設的時間間隔為1分鐘。
  • debug:當此屬性設定為true時,将列印出logback内部日志資訊,實時檢視logback運作狀态。預設值為false。

根節點​

​<configuration>​

​的子節點:

屬性一:設定上下文名稱​

​<contextName>​

每個logger都關聯到logger上下文,預設上下文名稱為“default”。但可以使用​

​<contextName>​

​設定成其他名字,用于區分不同應用程式的記錄。一旦設定,不能修改,可以通過%contextName來列印日志上下文名稱。

<contextName>logback</contextName>      

屬性二:設定變量​

​<property>​

用來定義變量值的标簽,​

​<property>​

​​ 有兩個屬性,name和value;其中name的值是變量的名稱,value的值時變量定義的值。通過​

​<property>​

​定義的值會被插入到logger上下文中。定義變量後,可以使“${}”來使用變量。

<property name="log.path" value=".\\logback.log"      

子節點一​

​<appender>​

appender用來格式化日志輸出節點,有倆個屬性name和class,class用來指定哪種輸出政策,常用就是控制台輸出政策和檔案輸出政策。

控制台輸出ConsoleAppender:

<!--輸出到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> 
            </filter> -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level
                %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>      

​<encoder>​

​表示對日志進行編碼:

  • %d{HH: mm:ss.SSS}——日志輸出時間
  • %thread——輸出日志的程序名字,這在Web應用以及異步任務進行中很有用
  • %-5level——日志級别,并且使用5個字元靠左對齊
  • %logger{36}——日志輸出者的名字
  • %msg——日志消息
  • %n——平台的換行符

ThresholdFilter為系統定義的攔截器,例如我們用ThresholdFilter來過濾掉ERROR級别以下的日志不輸出到檔案中。如果不用記得注釋掉,不然你控制台會發現沒日志~

輸出到檔案RollingFileAppender

另一種常見的日志輸出到檔案,随着應用的運作時間越來越長,日志也會增長的越來越多,将他們輸出到同一個檔案并非一個好辦法。RollingFileAppender用于切分檔案日志:

<!--輸出到檔案 -->
    <appender name="file"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logback.%d{yyyy-MM-dd_HH-mm}.log
            </fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36}
                - %msg%n</pattern>
        </encoder>
    </appender>      

其中重要的是rollingPolicy的定義,上例中​

​<fileNamePattern>logback.%d{yyyy-MM-dd}.log</fileNamePattern>​

​​定義了日志的切分方式——把每一天的日志歸檔到一個檔案中,​

​<maxHistory>30</maxHistory>​

​​表示隻保留最近30天的日志,以防止日志填滿整個磁盤空間。同理,可以使用%d{yyyy-MM-dd_HH-mm}來定義精确到分的日志切分方式。​

​<totalSizeCap>1GB</totalSizeCap>​

​用來指定日志檔案的上限大小,例如設定為1GB的話,那麼到了這個值,就會删除舊的日志。

子節點二​

​<root>​

root節點是必選節點,用來指定最基礎的日志輸出級别,隻有一個level屬性。

level:用來設定列印級别,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能設定為INHERITED或者同義詞NULL,預設是DEBUG。

可以包含零個或多個元素,辨別這個appender将會添加到這個loger。

"info">
        <appender-ref ref="console" />
        <appender-ref ref="file"      

子節點三​

​<loger>​

​<loger>​

​​用來設定某一個包或者具體的某一個類的日志列印級别、以及指定​

​<appender>​

​​。​

​<loger>​

​僅有一個name屬性,一個可選的level和一個可選的addtivity屬性。

  • name:用來指定受此loger限制的某一個包或者具體的某一個類。
  • level:用來設定列印級别,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,還有一個特俗值INHERITED或者同義詞NULL,代表強制執行上級的級别。如果未設定此屬性,那麼目前loger将會繼承上級的級别。

第一種:帶有loger的配置,不指定級别,不指定appender

<logger name="com.ahut.action"/>      

将控制action包下的所有類的日志的列印,但是并沒用設定列印級别,是以繼承他的上級​

​<root>​

​​的日志級别“info”;

沒有設定addtivity,預設為true,将此loger的列印資訊向上級傳遞;

沒有設定appender,此loger本身不列印任何資訊。

​​

​<root level="info">​

​​将root的列印級别設定為“info”,指定了名字為“console”的appender。

當執行com.ahur.action.DemoAction類的demo方法時,DemoAction 在包com.ahur.actionr中,是以首先執行​​

​<logger name="com.ahut.action"/>​

​​,将級别為“info”及大于“info”的日志資訊傳遞給root,本身并不列印;

root接到下級傳遞的資訊,交給已經配置好的名為“console”的appender處理,“console”appender将資訊列印到控制台;

第二種:帶有多個loger的配置,指定級别,指定appender

<logger name="com.ahut.action" level="INFO" additivity="false">
        <appender-ref ref="console"
    </logger>      

控制com.ahut.action.DemoAction類的日志列印,列印級别為“WARN”

additivity屬性為false,表示此loger的列印資訊不再向上級傳遞

指定了名字為“console”的appender

這時候執行com.ahut.action.DemoAction類的login方法時,先執行​

​<logger name="com.dudu.controller.LearnController" level="WARN" additivity="false">​

​​

,将級别為“WARN”及大于“WARN”的日志資訊交給此loger指定的名為“console”的appender處理,在控制台中打出日志,不再向上級root傳遞列印資訊。

當然如果你把additivity=”false”改成additivity=”true”的話,就會列印兩次,因為列印資訊向上級傳遞,logger本身列印一次,root接到後又列印一次。

多環境日志輸出

據不同環境(prod:生産環境,test:測試環境,dev:開發環境)來定義不同的日志輸出,在 logback-spring.xml中使用 springProfile 節點來定義,方法如下:

檔案名稱不是logback.xml,想使用spring擴充profile支援,要以logback-spring.xml命名

<!-- 測試環境+開發環境. 多個使用逗号隔開. -->
    <springProfile name="test,dev">
        <logger name="com.ahut.action" level="info"
    </springProfile>
    <!-- 生産環境. -->
    <springProfile name="prod">
        <logger name="com.ahut.action" level="ERROR"
    </springProfile>      

可以啟動服務的時候指定 profile (如不指定使用預設),如指定prod 的方式為:

java -jar xxx.jar –spring.profiles.active=prod

列印sql

<!-- 列印執行的sql name指定mapper所在的包,additivity設定為true時,父級也會列印相應的資訊,相當于列印多次 -->
<logger name="com.ahut.mapper" level="DEBUG" additivity="false">
    <appender-ref ref="console"
    <appender-ref ref="file"
</logger>      

總結

private Logger logger = LoggerFactory.getLogger(this.getClass());