springboot+logback日誌輸出企業實踐(上)

一句話概括:在java應用開發過程中,日誌輸出與記錄是重要一環,logback是當前的首選日誌框架,本文將對springboot+logback的使用及在企業的實踐進行詳細描述。

1.引言

在java應用開發過程中,日誌輸出與記錄是重要的一環,有了日誌,我們可以定位錯誤與異常,追蹤應用運行情況,記錄應用訪問時間等等。在學習hello world時就會使用System.out.println()來輸出內容,當涉及到複雜一點的日誌輸出,最好是引入成熟的日誌框架,曾經log4j是流行的日誌框架,現在已被它的繼任者logback替代,它更快,更小,更靈活。在springboot的開發中,默認已經自帶了logback,可直接使用。本文基本springboot+logback,結合在企業中的實踐,對日誌的輸出及配置進行詳細說明,具體有如下內容:

  • logback簡要介紹
  • 使用springboot+logback構建示例工程及配置描述
  • logback配置文件的詳述及使用

如需看源碼,本文示例工程地址https://github.com/mianshenglee/my-example/tree/master/springboot-logback-demo

2.logback簡介

logback官網地址http://logback.qos.ch,從官網的介紹, logback是log4j框架的作者開發的新一代日誌框架,是log4j的繼任者,它更快,更小, 效率更高、能夠適應各種運行環境,同時天然支持slf4j。 slf4j,即Simple Logging Facade For Java,它是對各類日誌框架的統一抽象,即定義了接口,具體使用哪個日誌 框架由運行時綁定實現。

logback主要由三個模塊構成,分別是logback-corelogback-classiclogback-access,其中logback-core是基礎核心,另外兩個均依賴它。 logback-classic實現了簡單日誌門面 SLF4J;而 logback-access 主要作爲一個與 Servlet 容器交互的模塊,如tomcat或者 jetty,提供與 HTTP 訪問相關的一些功能。

3. springboot默認日誌框架-logback

本章節將使用springboot+logback構建示例工程,並對logback基本配置進行描述。

3.1 springboot示例工程搭建

(1) 創建項目:通過Spring Initializr 頁面生成一個添加了web模塊及lombok模塊的 Spring Boot 項目。

(2)添加示例功能:

  • 首先添加幾個通用包:vo,controller,service,model,分別存放視圖層模型,控制層,服務層,數據模型層等代碼。
  • 針對用戶增刪改查功能,對應有數據模型User,UserController,UserService,統一返回視圖模型ResponseResult。

(3)添加日誌輸出

  • 在UserService類中添加lombok提供的@Slf4j註解,這樣可直接在此類中使用log進行日誌輸出,避免自己使用LoggerFactory.getLogger來新建。
  • 在對應的方法中使用debuginfowarnerror等方法輸出日誌。如log.debug("get user by id:{}", id)

注意:此處具體代碼不列出(詳細可看示例源碼)。

至此,示例工程構建完成,可正常運行工程,查看工程的依賴情況,可以發現,springboot已默認支持logback。如下:

logback依賴

3.2 日誌輸出與基本配置

3.2.1 日誌默認輸出

如上所示,默認情況下,springboot使用logback進行日誌輸出,輸出日誌爲INFO級別,輸出位置是控制檯。啓動示例工程,示例輸出如下:

默認日誌輸出

控制檯日誌輸出的內容格式很清晰,分別是

  • 時間日期:格式是yyyy-MM-dd HH:mm:ss.SSS
  • 日誌級別:輸出>=INFO級別的日誌(ERROR, WARN, INFO)
  • 進程ID
  • 分隔符:---
  • 線程名:線程名在方括號([])內
  • logger名:類的名稱
  • 日誌內容

3.2.2 基本配置

在springboot在配置文件application.properties中,可以設置日誌相關的內容,如下:

springboot日誌配置

關於日誌的配置有很多,後面我們主要使用自定義配置,因此不作詳細說明,此處主要講兩個,日誌級別控制及日誌文件輸出。

  • 日誌級別控制,設置格式爲logging.leve.*=LEVEL,其中*爲包名或logger名,LEVEL有:TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF

  • 日誌輸出到文件,默認日誌只輸出到控制檯,不寫文件,可以配置logging.file.namelogging.file.path來指定日誌輸出文件。logging.file.name設置文件, 會在項目的當前路徑下生成此文件名的日誌文件 。logging.path設置目錄,會在此目錄下創建spring.log文件。 默認情況下,日誌文件的大小達到10MB時會切分一次,產生新的日誌文件

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

3.3 自定義logback配置

上面在properties文件中對日誌進行基本的配置,但配置能力較弱,不夠靈活。因此一般都使用自定義配置,通過xml文件對logback的日誌輸出進行配置。

3.3.1 logback配置文件加載順序

在springboot應用中,對於logback的配置文件,默認情況下,配置文件放在src/main/resources下,支持的配置文件名稱如下:

  • logback-spring.xml
  • logback-spring.groovy
  • logback.xml
  • logback.groovy

Spring Boot官方推薦優先使用帶有-spring的文件名配置(如有logback-spring.xml,則不會使用logback.xml) 。當然,若需要對配置文件名進行修改,或者希望把配置文件放到其它目錄下,可以通過logging.config屬性指定自定義的名字,如logging.config=classpath:config/log-config.xml,則使用resources/config下的log-config.xml配置。

注,一般情況下,按默認規則(在resources目錄下,使用logback-spring.xml)即可。另外有了這個配置文件後,前面提到的在properties文件中的logging配置則不需要了。

3.3.2 logback配置文件示例

這裏先直接給出配置文件的示例,後面章節將對配置文件內容進行詳細說明。如下所示,配置文件主要功能是把日誌按格式輸出到控制檯和文件中,並且文件按日誌輸出級別分別輸出到獨立文件,文件按時間滾動(每天一個日誌文件,保留30天)。完整配置內容可見源碼中的logback-spring.xml文件。

<configuration scan="true" scanPeriod="1 seconds">
    ...//略
    <!-- 日誌輸出格式 -->
    <property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%15thread] [%40.40logger{40}] [%10method,%line] : %msg%n"/>
    <!-- 控制檯輸出日誌 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>${log.pattern}</pattern>
        </layout>
    </appender>

    <!-- 文件輸出日誌, 滾動(時間/文件大小)輸出策略 -->
    <appender name="DEBUGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 過濾器,只記錄debug級別的日誌 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <!-- 日誌文件路徑及文件名 -->
        <File>${log.path}/${logfile.prefix}-debug.log</File>
        <!-- 日誌記錄器的滾動策略,按日期記錄 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日誌輸出格式 -->
            <FileNamePattern>${log.path}/${logfile.prefix}-debug.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!-- 日誌保留天數 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${log.pattern}</Pattern>
        </layout>
    </appender>
    ...//略
    <!-- 日誌級別,不向上級傳遞日誌內容,日誌按appender-ref輸出 -->
    <logger name="me.mason.demo.simplelogback.service.UserService" level="WARN" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
    <!-- 日誌輸出 -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DEBUGFILE"/>
        ...//略
    </root>
</configuration>

4. logback配置文件詳述

logback配置文件決定日誌輸出格式、日誌輸出位置、輸出文件策略等內容,因此需要對logback配置文件的結構及相關元素內容進行了解。

4.1 配置文件結構

配置文件總體來說內容比較簡單,主要三個元素:

配置主要元素

這三個元素中,logger和root可視爲同一類,都是日誌組件,可以把root當作是特殊logger,是根,必須配置。logger配置解答從哪裏獲取日誌,輸出什麼級別日誌問題。appender配置是指出日誌以什麼格式輸出,日誌如何過濾,輸出文件後如何處理的問題。另外,還有可選的property及contextName元素,分別變量和應用上下文名稱。

4.2 根元素configuration

4.2.1 屬性配置

根元素configuration有三個屬性可以設置,如下:

  • debug:默認爲false,若設置爲true,則打印出logback內部日誌信息

  • scan:默認值爲true,若設置爲true,配置文件如果發生改變,將會被重新加載。
  • scanPeriod:與scan配合使用,當scan爲true時,此屬性生效,默認的時間間隔爲1分鐘,設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。如可以設置爲scanPeriod="30 seconds"每30秒檢測一次。

4.2.2 定義上下文名稱和變量

  • contextName元素,每一個日誌組件(logger)都會關聯到日誌上下文,默認上下文名稱是'default',用於標識應用,如果多個應用輸出到同一個地方,就有必要使用%contextName來區別。
  • property元素,定義變量,有name和value屬性,定義變量後,可以使“${name}”來使用變量。在配置中多個地方的值使用到相同的內容時,就有必要把相同內容設置變量,通過引用來設置。如示例工程中的日誌文件名稱前綴、日誌路徑、日誌輸出格式。

注意,定義的變量只能在配置文件的值中進行引用,不能在元素屬性中引用。如配置文件中有很多屬性是class,裏面的內容只能寫類的全路徑,儘管類前綴都相同,但不能用變量替換。

4.3 日誌輸出組件appender

此元素是主要配置項,表示以什麼格式輸出,日誌如何過濾,輸出文件後如何處理。appender結構如下:

appender結構

appender 有兩個屬性 nameclass;name指定appender名稱,class指定appender的全限定名。appender 默認有以下幾種:

  • ConsoleAppender:把日誌添加到控制檯,類名ch.qos.logback.core.ConsoleAppender
  • FileAppender:把日誌添加到文件,類名ch.qos.logback.core.FileAppender
  • RollingFileAppender:滾動記錄文件,FileAppender的子類,當符合條件(大小、時間),日誌進行切分,記錄到其他文件。類名:ch.qos.logback.core.rolling.RollingFileAppender

實踐過程中,一般使用ConsoleAppender及RollingFileAppender即可,若需要自定義如把日誌輸出到消息隊列,可以自定義實現 AppenderBase 接口。

ConsoleAppender比較簡單,只需要使用layout元素,按日誌輸出格式即可,如下:

<!-- 控制檯輸出日誌 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>${log.pattern}</pattern>
    </layout>
</appender>

RollingFileAppender的配置相對多一點,包括File、filter,rollingPolicy,encoder和layout元素。其中filter可以過濾日誌,因此,若需要把日誌按級別輸出到不同的文件中,因此,定義多個RollingFileAppender(如對應DEBUG、INFO、WARN、ERROR),分別按日誌級別過濾即可。下面分別進行說明:

4.3.1 File配置

配置文件輸出的路徑及文件名,一般把路徑和文件名前綴定義到變量(property中),如下:

<!--日誌文件前綴,即應用名稱 -->
<property name="logfile.prefix" value="logback-demo"/>
<!--日誌路徑,可寫相對路徑,也可寫絕對路徑 -->
<property name="log.path" value="logs"/>
...//略
<File>${log.path}/${logfile.prefix}-debug.log</File>

4.3.2 filter配置

filter可以爲appender 添加一個或多個過濾器,對日誌進行過濾。過濾器有ThresholdFilterLevelFilter,前者是臨界值過濾器,過濾掉低於指定臨界值的日誌;後者是級別過濾器,根據日誌級別進行過濾, 如果日誌級別等於配置級別 ,過濾器會根據onMath(符合過濾條件的操作) 和 onMismatch(不符合過濾條件的操作)接收(ACCEPT)或拒絕(DENY)日誌。 按前面需求,把日誌按不同級別分別輸出到各自文件中,需要多個RollingFileAppender元素,每個元素下對應的level是DEBUG,INFO,WARN和ERROR。

<!-- 過濾器,只記錄debug級別的日誌 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>DEBUG</level>
    <OnMismatch>DENY</OnMismatch>
    <OnMatch>ACCEPT</OnMatch>
</filter>

4.3.3 rollingPolicy配置

此元素描述滾動策略,有TimeBasedRollingPolicySizeAndTimeBasedRollingPolicyFixedWindowRollingPolicySizeBasedTriggeringPolicy。分別是基於時間滾動,基於大小和時間滾動,固定窗口滾動和大小觸發,其中FixedWindowRollingPolicy一般和SizeBasedTriggeringPolicy同時使用。下面以TimeBasedRollingPolicy爲例,以天爲單位輸出日誌,每天一個日誌。

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <!-- 日誌輸出格式 -->
    <FileNamePattern>${log.path}/${logfile.prefix}-debug.%d{yyyy-MM-dd}.log</FileNamePattern>
    <!-- 日誌保留天數 -->
    <maxHistory>30</maxHistory>
</rollingPolicy>

FileNamePattern表示日誌的路徑及名稱,此處是按日期輸出,即%d{yyyy-MM-dd}格式。maxHistory表示日誌最多保留天數,大於這些天數後,前面的日誌會刪除。

對於SizeAndTimeBasedRollingPolicy,如下所示:

<!-- 按日期滾動 -->
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<!-- 文件大小最大是100M,保存60日,總大小最大爲20G -->
<maxFileSize>100MB</maxFileSize>    
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>

注意,%i%d標識符都是強制性的。 每當日誌文件在當前時間段結束之前達到文件最大值時,它將以遞增的%d索引存檔,從0開始。

4.3.4 layout配置

layout元素較簡單,只需要設置輸出的格式即可。

<property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%15thread] %40.40logger{40} [%10method,%line] : %msg%n"/>
...//略
<layout class="ch.qos.logback.classic.PatternLayout">
    <Pattern>${log.pattern}</Pattern>
</layout>

4.3.5 輸出格式控制

對於日誌輸出格式的控制,使用logback的保留字進行控制,保留字很多,建議查閱官網文檔,下面對常用進行說明:

保留字 作用
c{length} lo{length} logger{length} 輸出日誌的logger名,可有一個整型參數,功能是縮短logger名,最右的點符號之後的類名始終顯示,設置爲0表示只輸入logger最右邊點符號之後的字符串。
C{length} class{length} 輸出執行記錄請求的調用者的全限定名。參數與上面的一樣。儘量避免使用,除非執行速度不造成任何問題。
contextName cn 輸出上下文名稱。
d{pattern} date{pattern} 輸出日誌的打印日誌,模式語法與java.text.SimpleDateFormat兼容。
L / line 輸出執行日誌請求的行號。儘量避免使用,除非執行速度不造成任何問題。
m / msg / message 輸出應用程序提供的信息。
M / method 輸出執行日誌請求的方法名。儘量避免使用,除非執行速度不造成任何問題。
n 輸出平臺相關的分行符“\n”或者“\r\n”。
p / le / level 輸出日誌級別。
t / thread 輸出產生日誌的線程名。

另外,格式還有一個對齊功能,通過在%後面添加-.及數字進行控制。符號-是可選修飾符,表示是左對齊,接着是可選的最小寬度修飾符,用十進制數表示。如果字符小於最小寬度,則左填充或右填充,默認是左填充(即右對齊),填充符爲空格。最大寬度修飾符,符號是點號"."後面加十進制數。如果字符大於最大寬度,則從前面截斷。點符號“.”後面加減號“-”在加數字,表示從尾部截斷。

例如:%-40.40logger{40} 表示按40字符輸出logger名,左對齊,若小於40字符的則填充空格,超過40則從左邊截斷。

對於控制檯,還可以控制顏色,如前面springboot的默認輸出就有顏色,如下:

格式 描述
%black 黑色
%red 紅色
%green 綠色
%yellow 黃色
%blue 藍色
%magenta 品紅
%cyan 青色
%white 白色
%gray 灰色
%highlight 高亮色
%bold 強化上面的顏色,例如%boldRed,%boldBlack

4.4 日誌組件logger及root

logger用來設置某一個類或者某個包的日誌輸出級別、以及關聯appender指定輸出位置,有三個屬性:

  • name:指定的包名或者類名
  • level:輸出日誌級別,如果未設置此級別,那麼當前logger會向上繼承最近一個非空級別,級別以name區分,如x和x.y,x則是x.y的父級。
  • additivity:是否將日誌向上級傳遞,默認爲 true

logger 通過設置子節點appender-ref來指定日誌輸出位置,可以設置多個appender-refroot是一個特殊的logger, 是所有logger的根節點,元素名爲root,沒有父級別,只有一個屬性level,默認爲DEBUG 。

4.4.1 logger配置,

此處對某個具體的類進行配置輸出進行設置,由於設置了WARN級別,additivitytrue,而且關聯STDOUT的appender,因此此類的>=WARN的日誌會輸出到控制檯。同時會把日誌上傳到父級,即root。若root也有配置STDOUT的輸出的話,會發現此日誌在控制檯輸出兩次。若additivityfalse,則不會。

<!-- 日誌級別,不向上級傳遞日誌內容,日誌按appender-ref輸出 -->
<logger name="me.mason.demo.simplelogback.service.UserService" level="WARN" additivity="true">
    <appender-ref ref="STDOUT"/>
</logger>

4.4.2 root配置

logger可以不配置,但root元素是必須配置的,需要告訴logback把日誌輸出到哪裏。如下,只需要關聯日誌需要輸出的appender即可。前面已經有STDOUT控制檯及按日誌級別設置了各個文件appender,此處直接關聯即可。

<root level="DEBUG">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="DEBUGFILE"/>
    <appender-ref ref="INFOFILE"/>
    <appender-ref ref="WARNFILE"/>
    <appender-ref ref="ERRORFILE"/>
</root>

經過以上的配置,彙總到logback-spring.xml中,啓動運行程序,即可看到控制檯會按格式輸出日誌,同時會在應用根目錄下創建logs目錄存放日誌文件,且日誌格式是按配置輸出,如下:

日誌文件

5. 總結

本篇文章針對springboot應用開發中,如何使用logback,結合在企業中的實踐,創建springboot示例,然後對logback的配置進行詳細說明,實現按日誌級別輸出日誌文件功能。但在實際開發中,還有不少需要改進的地方,包括多環境配置,日誌輸出效率問題,分佈式系統請求ID追蹤問題等,將在下篇文章進行講解。

本文中使用的示例代碼已放在githubhttps://github.com/mianshenglee/my-example/tree/master/springboot-logback-demo,有興趣的同學可以pull代碼,結合示例一起學習。

參考資料

往期文章

關注我的公衆號,獲取更多技術記錄:

mason

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章