1. 程式人生 > >Spring Boot(二)——Spring Boot日誌

Spring Boot(二)——Spring Boot日誌

一、日誌框架

在Java中,輸出日誌需要使用一個或者多個日誌框架,這些框架提供了必要的物件、方法和配置來傳輸訊息。Java在java.util.logging包中提供了一個預設的框架。除此之外,還有很多其它第三方框架,包括Log4j、Logback以及tinylog。還有其它一些開發包,例如SLF4J和Apache Commons Logging,它們提供了一些抽象層,對你的程式碼和日誌框架進行解耦,從而允許你在不同的日誌框架中進行切換。

如何選擇一個日誌解決方案,這取決於你的日誌需求的複雜度、和其它日誌解決方案的相容性、易用性以及個人喜好。Logback基於log4j之前的版本開發(版本1),因此它們的功能集合都非常類似。然而,Log4j在最新版本(版本2)中引用了一些改進,例如支援多API,並提升了在用Disruptor庫的效能。

抽象層(日誌門面)

諸如SLF4J這樣的抽象層,會將你的應用程式從日誌框架中解耦。應用程式可以在執行時選擇繫結到一個特定的日誌框架(例如java.util.logging、Log4j或者Logback),這通過在應用程式的類路徑中新增對應的日誌框架來實現。如果在類路徑中配置的日誌框架不可用,抽象層就會立刻取消呼叫日誌的相應邏輯。抽象層可以讓我們更加容易地改變專案現有的日誌框架,或者整合那些使用了不同日誌框架的專案。
日誌門面

二、Spring Boot預設日誌

Spring Boot預設的日誌抽象層

SLF4J——Simple Logging Facade For Java,它是一個針對於各類Java日誌框架的統一Facade抽象。Java日誌框架眾多——常用的有java.util.logging, log4j, logback,commons-logging, Spring框架使用的是Jakarta Commons Logging API (JCL)。而SLF4J定義了統一的日誌抽象介面,而真正的日誌實現則是在執行時決定的——它提供了各類日誌框架的binding。

Spring Boot預設的日誌實現層

Logback是log4j框架的作者開發的新一代日誌框架,它效率更高、能夠適應諸多的執行環境,同時天然支援SLF4J。

注: 預設情況下,Spring Boot會用Logback來記錄日誌,並用INFO級別輸出到控制檯。

三、Spring Boot日誌配置

Spring Boot官方推薦優先使用帶有 -spring 的檔名作為你的日誌配置(如使用logback-spring.xml),命名為logback-spring.xml的日誌配置檔案,spring boot可以為它新增一些spring boot特有的配置項(如,springProfile等)。

下面是Spring Boot自定義日誌配置檔案的解析:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <!--定義日誌存放的位置-->
    <springProperty scope="context" name="gunsLogPath" source="log.path"
                    defaultValue="guns-logs"/>

    <!-- ****************************************************************************************** -->
    <!-- ****************************** 本地開發只在控制檯列印日誌 ************************************ -->
    <!-- ****************************************************************************************** -->
    <springProfile name="local">

        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--encoder 預設配置為PatternLayoutEncoder-->
            <encoder>
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
        </appender>

        <root level="info">
            <appender-ref ref="STDOUT"/>
        </root>

        <logger name="com.stylefeng.guns" level="debug" additivity="false">
            <appender-ref ref="STDOUT"/>
        </logger>

    </springProfile>

    <!-- ****************************************************************************************** -->
    <!-- ********************** 放到伺服器上不管在什麼環境都只在檔案記錄日誌 **************************** -->
    <!-- ****************************************************************************************** -->
    <springProfile name="!local">

        <!-- 日誌記錄器,日期滾動記錄 -->
        <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在記錄的日誌檔案的路徑及檔名 -->
            <file>${gunsLogPath}/log_error.log</file>
            <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
                而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${gunsLogPath}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
                命名日誌檔案,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>2MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式記錄日誌 -->
            <append>true</append>
            <!-- 日誌檔案的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日誌檔案只記錄error級別的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>

        <!-- 日誌記錄器,日期滾動記錄 -->
        <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在記錄的日誌檔案的路徑及檔名 -->
            <file>${gunsLogPath}/log_total.log</file>
            <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
                而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${gunsLogPath}/total/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
                命名日誌檔案,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>2MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式記錄日誌 -->
            <append>true</append>
            <!-- 日誌檔案的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
        </appender>

        <root level="info">
            <appender-ref ref="FILE_ERROR"/>
            <appender-ref ref="FILE_ALL"/>
        </root>

    </springProfile>

</configuration>

注:以上程式碼來自碼雲開源框架guns

根節點<configuration>包含的屬性

scan:當此屬性設定為true時,配置檔案如果發生改變,將會被重新載入,預設值為true。
scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間單位,預設單位是毫秒。當scan為true時,此屬性生效。預設的時間間隔為1分鐘。
debug:當此屬性設定為true時,將打印出logback內部日誌資訊,實時檢視logback執行狀態。預設值為false。

<springProperty>標籤

用來定義變數值的標籤, 有兩個屬性,name和value;其中name的值是變數的名稱,value的值時變數定義的值。通過定義的值會被插入到logger上下文中。定義變數後,可以使“${}”來使用變數。

<file>${gunsLogPath}/log_error.log</file>

<appender>標籤

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

輸出到控制檯(ConsoleAppender)

        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--encoder 預設配置為PatternLayoutEncoder-->
            <encoder>
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
        </appender>

輸出到檔案(RollingFileAppender)

<!-- 日誌記錄器,日期滾動記錄 -->
        <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在記錄的日誌檔案的路徑及檔名 -->
            <file>${gunsLogPath}/log_error.log</file>
            <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
                而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${gunsLogPath}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
                命名日誌檔案,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>2MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式記錄日誌 -->
            <append>true</append>
            <!-- 日誌檔案的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日誌檔案只記錄error級別的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>

<encoder>標籤

<encoder>表示對日誌進行編碼:

  • %d{yyyy-MM-dd HH:mm:ss.SSS}——日誌輸出時間
  • %thread——輸出日誌的程序名字,這在Web應用以及非同步任務處理中很有用
  • %-5level——日誌級別,並且使用5個字元靠左對齊
  • %logger——日誌輸出者的名字
  • %msg——日誌訊息
  • %n——平臺的換行符

<filter>標籤

此日誌檔案只記錄error級別的

            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>

<root>標籤

        <root level="info">
            <appender-ref ref="STDOUT"/>
        </root>

<root>標籤是必選的,用來指定最基礎的日誌輸出級別,只有一個level屬性。

level: 用來設定列印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能設定為INHERITED或者同義詞NULL。預設是DEBUG。可以包含零個或多個元素,標識這個appender將會新增到這個logger。

<logger>標籤

        <logger name="com.stylefeng.guns" level="debug" additivity="false">
            <appender-ref ref="STDOUT"/>
        </logger>

<logger>用來設定某一個包或者具體的某一個類的日誌列印級別、以及指定<appender><logger>僅有一個name屬性,一個可選的level和一個可選的addtivity屬性。

name:用來指定受此loger約束的某一個包或者具體的某一個類。
level:用來設定列印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,還有一個特俗值INHERITED或者同義詞NULL,代表強制執行上級的級別。如果未設定此屬性,那麼當前loger將會繼承上級的級別。
addtivity:是否向上級loger傳遞列印資訊。預設是true。

<springProfile>標籤

<springProfile>標籤為多環境日誌輸出,是Spring Boot自帶的配置屬性。

四、參考資料

Java日誌終極指南
Java日誌框架那些事兒(上)
Java日誌框架那些事兒(下)
Spring Boot 日誌配置(超詳細)
Spring Boot乾貨系列:(七)預設日誌logback配置解析