首頁/ 汽車/ 正文

一步一步帶你熟悉SpringBoot 配置slf4j+logback

前言

對於一個web專案來說,日誌框架是必不可少的,日誌的記錄可以幫助我們在開發以及維護過程中快速的定位錯誤。相信很多人聽說過slf4j,log4j,logback,JDK Logging等跟日誌框架有關的詞語,所以這裡也簡單介紹下他們之間的關係。

關係

首先slf4j可以理解為規則的制定者,是一個抽象層,定義了日誌相關的介面。log4j,logback,JDK Logging都是slf4j的實現層,只是出處不同,當然使用起來也就各有千秋,這裡放一張網上的圖更明瞭的解釋了他們之間的關係:

一步一步帶你熟悉SpringBoot 配置slf4j+logback

為什麼使用slf4j+logback

我使用這個框架是因為一開始接觸的時候就用的這個,後來在網上了解到slf4j+logback也確實當下最流行的日誌框架,並且自己用著也確實很順手,也就一直用了下來。

在Spring boot中使用slf4j+logback日誌框架

新增配置檔案

在Spring boot使用是非常方便的,不需要我們有什麼額外的配置,因為Spring boot預設支援的就是slf4j+logback的日誌框架,想要靈活的定製日誌策略,只需要我們在src/main/resources下新增配置檔案即可,只是預設情況下配置檔案的命名需要符合以下規則:

logback。xml

logback-spring。xml

其中logback-spring。xml是官方推薦的,

並且只有使用這種命名規則,才可以配置不同環境使用不同的日誌策略這一功能。

配置檔案詳解

首先介紹配置檔案的關鍵節點:

框架介紹

:根節點,有三個屬性:

scan:當配置檔案發生修改時,是否重新載入該配置檔案,兩個可選值true or false,預設為true。

scanPeriod:檢測配置檔案是否修改的時間週期,當沒有給出時間單位時預設單位為毫秒,預設值為一分鐘,需要注意的是這個屬性只有在scan屬性值為true時才生效。

debug:是否列印loback內部日誌資訊,兩個可選值true or false,預設為false。

根節點有三個重要的子節點,正是這三個子節點的不同組合構成配置檔案的基本框架,使得logback。xml配置檔案具備很強的靈活性:

:定義日誌策略的節點,一個日誌策略對應一個,一個配置檔案中可以有零個或者多該節點,但一個配置檔案如果沒有定義至少一個,雖然程式不會報錯,但就不會有任何的日誌資訊輸出,也失去了意義,該節點有兩個必要的屬性:

name:指定該節點的名稱,方便之後的引用。

class:指定該節點的全限定名,所謂的全限定名就是定義該節點為哪種型別的日誌策略,比如我們需要將日誌輸出到控制檯,就需要指定class的值為ch。qos。logback。core。ConsoleAppender;需要將日誌輸出到檔案,則class的值為ch。qos。logback。core。FileAppender等。

:用來設定某個包或者類的日誌列印級別,並且可以引用繫結日誌策略,有三個屬性:

name:用來指定受此約束的包或者類。

level:可選屬性,用來指定日誌的輸出級別,如果不設定,那麼當前會繼承上級的級別。

additivity:是否向上級傳遞輸出資訊,兩個可選值true or false,預設為true。

在該節點內可以新增子節點,該節點有一個必填的屬性ref,值為我們定義的節點的name屬性的值。

:根一個特殊的,即預設name屬性為root的,因為是根,所以不存在向上傳遞一說,故沒有additivity屬性,所以該節點只有一個level屬性。

介紹了根節點的三個主要的子節點,下面再介紹兩個不那麼重要但可以瞭解的子節點:

:設定上下文名稱,每個都關聯到上下文,預設上下文名稱為default,但可以使用設定成其他名字,用於區分不同應用程式的記錄,一旦設定,不能修改,可以透過 %contextName 來列印日誌上下文名稱,一般來說我們不用這個屬性,可有可無。

:用來定義變數的節點,定義變數後,可以使${}來使用變數,兩個屬性,當定義了多個的時候還是很有用的:

name:變數名

value:變數值

好了,介紹了上邊的節點我們就已經可以搭建一個簡單的配置檔案框架了,如下:

<?xml version=“1。0” encoding=“UTF-8”?><!—— 一般根節點不需要寫屬性了,使用預設的就好 ——> demo <!—— 該變數代表日誌檔案存放的目錄名 ——> <!—— 該變數代表日誌檔名 ——> <!——定義一個將日誌輸出到控制檯的appender,名稱為STDOUT ——> <!—— 內容待定 ——> <!——定義一個將日誌輸出到檔案的appender,名稱為FILE_LOG ——> <!—— 內容待定 ——> <!—— 指定com。demo包下的日誌列印級別為INFO,但是由於沒有引用appender,所以該logger不會列印日誌資訊,日誌資訊向上傳遞 ——> <!—— 指定最基礎的日誌輸出級別為DEBUG,並且綁定了名為STDOUT的appender,表示將日誌資訊輸出到控制檯 ——>

上面搭建了框架,定義了一個輸出到控制檯的ConsoleAppender以及輸出到檔案的FileAppender,下面來細說這兩個最基本的日誌策略,並介紹最常用的滾動檔案策略的RollingFileAppender,這三種類型的日誌策略足夠我們的日常使用。

輸出到控制檯的ConsoleAppender的介紹:

先給出一個demo:

<!——定義一個將日誌輸出到控制檯的appender,名稱為STDOUT ——> [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n

ConsoleAppender的功能是將日誌輸出到控制檯,有一個節點用來指定日誌的輸出格式,在較早以前的版本還有一個節點也是相同的作用,但是官方推薦使用encoder節點,所以這裡我們介紹encoder節點即可。

節點介紹

該節點主要做兩件事:

把日誌資訊轉換成位元組陣列

將位元組陣列寫到輸出流

該節點的子節點作用就是定義日誌的格式,即定義一條日誌資訊包含哪些內容,例如當前時間,在程式碼中的行數執行緒名等。需要哪些內容由我們自己定義,按照%+轉換符的格式定義,下面列出常用的轉換符:

%date{}:輸出時間,可以在花括號內指定時間格式,例如-%data{yyyy-MM-dd HH:mm:ss},格式語法和java。text。SimpleDateFormat一樣,可以簡寫為%d{}的形式,使用預設的格式時可以省略{}。

%logger{}:日誌的logger名稱,可以簡寫為%c{},%lo{}的形式,使用預設的引數時可以省略{},可以定義一個整形的引數來控制輸出名稱的長度,有下面三種情況:

不輸入表示輸出完整的名稱

輸入0表示只輸出最右邊點號之後的字串

輸入其他數字表示輸出小數點最後邊點號之前的字元數量

%thread:產生日誌的執行緒名,可簡寫為%t

%line:當前列印日誌的語句在程式中的行號,可簡寫為%L

%level:日誌級別,可簡寫為%le,%p

%message:程式設計師定義的日誌列印內容,可簡寫為%msg,%m

%n:換行,即一條日誌資訊佔一行

介紹了常用的轉換符,我們再看看上邊的例子中我們定義的格式:

[Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n

日誌的格式一目瞭然,可以看出我們在最前面加了[eran]的字串,這裡是我個人的使用習慣,一般將專案名統一展現在日誌前邊,而且在每個轉換符之間加了空格,這更便於我們檢視日誌,並且使用了>>字串來將%msg分割開來,更便於我們找到日誌資訊中我們關注的內容,這些東西大家可以自己按照自己的喜好來。

輸出到檔案的FileAppender

先給出一個demo:

<!——定義一個將日誌輸出到檔案的appender,名稱為FILE_LOG ——> D:/test。log true [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n

FileAppender表示將日誌輸出到檔案,常用幾個子節點:

:定義檔名和路徑,可以是相對路徑 , 也可以是絕對路徑 , 如果路徑不存在則會自動建立

:兩個值true和false,預設為true,表示每次日誌輸出到檔案走追加在原來檔案的結尾,false則表示清空現存檔案

:和ConsoleAppender一樣

顯而易見,樣例中我們的日誌策略表示,每次將日誌資訊追加到D:/test。log的檔案中。

滾動檔案策略RollingFileAppender介紹

按時間滾動TimeBasedRollingPolicy

demo如下:

<!——滾動策略,按照時間滾動 TimeBasedRollingPolicy——> D:/logs/test。%d{yyyy-MM-dd}。log <!—— 只保留近七天的日誌 ——> 7 <!—— 用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌 ——> 1GB [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n

RollingFileAppender是非常常用的一種日誌型別,表示滾動紀錄檔案,先將日誌記錄到指定檔案,當符合某種條件時,將日誌記錄到其他檔案,常用的子節點:

:滾動策略,透過屬性class來指定使用什麼滾動策略,最常用是按時間滾動TimeBasedRollingPolicy,即負責滾動也負責觸發滾動,有以下常用子節點:

:指定日誌的路徑以及日誌檔名的命名規則,一般根據日誌檔名+%d{}。log來命名,這邊日期的格式預設為yyyy-MM-dd表示每天生成一個檔案,即按天滾動yyyy-MM,表示每個月生成一個檔案,即按月滾動

:可選節點,控制儲存的日誌檔案的最大數量,超出數量就刪除舊檔案,比如設定每天滾動,且 是7,則只儲存最近7天的檔案,刪除之前的舊檔案

:同上

:這個節點表示設定所有的日誌檔案最多佔的記憶體大小,當超過我們設定的值時,logback就會刪除最早建立的那一個日誌檔案。

以上就是關於RollingFileAppender的常用介紹,上面的demo的配置也基本滿足了我們按照時間滾動TimeBasedRollingPolicy生成日誌的要求,下面再介紹一種常用的滾動型別SizeAndTimeBasedRollingPolicy,即按照時間和大小來滾動。

按時間和大小滾動SizeAndTimeBasedRollingPolicy

demo如下:

D:/logs/test。%d{yyyy-MM-dd}。%i。log <!—— 單個檔案的最大記憶體 ——> 100MB <!—— 只保留近七天的日誌 ——> 7 <!—— 用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌 ——> 1GB [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n

仔細觀察上邊demo中的會發現比TimeBasedRollingPolicy中定義的多了。%i的字元,這個很關鍵,在SizeAndTimeBasedRollingPolicy中是必不可少的。

上邊的demo中多了一個節點,這裡介紹下,其他的節點上邊已經解釋過,這裡就不再贅述。

:表示單個檔案佔用的最大記憶體大小,當某個檔案超過這個值,就會觸發滾動策略,產生一個新的日誌檔案。

日誌過濾

級別介紹

在說級別過濾之前,先介紹一下日誌的級別資訊:

TRACE

DEBUG

INFO

WARN

ERROR

上述級別從上到下由低到高,我們開發測試一般輸出DEBUG級別的日誌,生產環境配置只輸出INFO級別甚至只輸出ERROR級別的日誌,這個根據情況而定,很靈活。

過濾節點介紹

過濾器通常配置在Appender中,一個Appender可以配置一個或者多個過濾器,有多個過濾器時按照配置順序依次執行,當然也可以不配置,其實大多數情況下我們都不需要配置,但是有的情況下又必須配置,所以這裡也介紹下常用的也是筆者曾經使用過的兩種過率機制:級別過濾器LevelFilter和臨界值過濾器ThresholdFilter。

在此之前先說下的概念,首先一個過濾器的所有返回值有三個,每個過濾器都只返回下面中的某一個值:

DENY:日誌將被過濾掉,並且不經過下一個過濾器

NEUTRAL:日誌將會到下一個過濾器繼續過濾

ACCEPT:日誌被立即處理,不再進入下一個過濾器

級別過濾器LevelFilter

過濾條件:只處理INFO級別的日誌,格式如下:

INFO ACCEPT DENY

:日誌級別

:配置滿足過濾條件的處理方式

:配置不滿足過濾條件的處理方式

就如上邊的demo中的配置一樣,設定了級別為INFO,滿足的日誌返回ACCEPT即立即處理,不滿足條件的日誌則返回DENY即丟棄掉,這樣經過這一個過濾器就只有INFO級別的日誌會被打印出輸出。

臨界值過濾器ThresholdFilter

過濾條件:只處理INFO級別之上的日誌,格式如下:

INFO

當日志級別等於或高於臨界值時,過濾器返回NEUTRAL,當日志級別低於臨界值時,返回DENY。

帶過濾器的

下面給出一個帶過濾器的

D:/logs/test。%d{yyyy-MM-dd}。%i。log <!—— 單個檔案的最大記憶體 ——> 100MB <!—— 只保留近七天的日誌 ——> 7 <!—— 用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌 ——> 1GB [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n <!—— 只處理INFO級別以及之上的日誌 ——> INFO <!—— 只處理INFO級別的日誌 ——> INFO ACCEPT DENY

上邊的demo中,我們給按時間和大小滾動SizeAndTimeBasedRollingPolicy的滾動型別加上了過濾條件。

非同步寫入日誌AsyncAppender

都知道,我們的日誌語句是嵌入在程式內部,如果寫入日誌以及程式執行的處於一個序列的狀態,那麼日誌的記錄就必然會阻礙程式的執行,加長程式的響應時間,無疑是一種極為損耗效率的方式,所以實際的專案中我們的日誌記錄一般都用非同步的方式來記錄,這樣就和主程式形成一種並行的狀態,不會影響我們程式的執行,這也是我們效能調優需要注意的一個點。

AsyncAppender並不處理日誌,只是將日誌緩衝到一個BlockingQueue裡面去,並在內部建立一個工作執行緒從佇列頭部獲取日誌,之後將獲取的日誌迴圈記錄到附加的其他appender上去,從而達到不阻塞主執行緒的效果。因此AsynAppender僅僅充當事件轉發器,必須引用另一個appender來寫日誌。

<!—— 不丟失日誌。預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 ——> 0 <!—— 更改預設的佇列的深度,該值會影響效能。預設值為256 ——> 512 <!—— 新增附加的appender,最多隻能新增一個 ——>

常用節點:

:預設情況下,當BlockingQueue還有20%容量,他將丟棄TRACE、DEBUG和INFO級別的日誌,只保留WARN和ERROR級別的日誌。為了保持所有的日誌,設定該值為0。

:BlockingQueue的最大容量,預設情況下,大小為256。

:新增附加的,最多隻能新增一個

節點介紹

上邊花費了很長的篇幅介紹了的相關內容,現在來詳細介紹下節點以及節點的相關內容。

上文已經簡單介紹了節點的屬性以及子節點,這裡我們就舉例來說明在logback-spring。xml檔案中,該節點到底扮演怎樣的角色,以及他的執行原理,看下邊的demo:

首先在這裡給出專案結構:

一步一步帶你熟悉SpringBoot 配置slf4j+logback

下面定義兩個以及

<!—— logger1 ——> <!—— logger2 ——> <!—— 指定最基礎的日誌輸出級別為DEBUG,並且綁定了名為STDOUT的appender,表示將日誌資訊輸出到控制檯 ——>

當存在多個時,會有父級子級的概念,日誌的處理流程是先子級再父級,當然是最高級別,怎樣區分級別大小呢,根據name屬性指定的包名來判斷,包名級別越高則的級別越高,跟我們定義的順序無關。

上邊我們定義了logger1和logger2,很明顯看出logger1是logger2的父級,以本例給出多個之間的執行流程圖:

一步一步帶你熟悉SpringBoot 配置slf4j+logback

流程圖看著一目瞭然,這裡就不再贅述,只是在實際的專案中我們一般都不讓輸出日誌,統一放在節點中輸出,所以一般不給節點新增,當然這個按實際需要可以靈活配置。

配置profile

profile即根據不同的環境使用不同的日誌策略,這裡舉例開發和生產環境:

<!—— 開發環境輸出到控制檯 ——> <!—— 生產環境輸出到檔案 ——>

可以看到我們只需要在節點的外邊再套一層就可以了,並且指定name屬性的值,在配置檔案裡邊配置好之後,怎麼啟用,這裡介紹兩種方式:

執行jar包時新增引數:

java -jar xxx。jar ——spring。profiles。active=prod

在專案的application。properties配置檔案中新增:

spring。profiles。active=prod

整合

最後將所有的模組整合在一起形成一個完整的配置檔案:

<?xml version=“1。0” encoding=“UTF-8”?> <!——定義一個將日誌輸出到控制檯的appender,名稱為STDOUT ——> [%contextName]%date [%thread %line] %level >> %msg >> %logger{10}%n <!——定義一個將日誌輸出到檔案的appender,名稱為FILE_LOG ——> D:/test。log true [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n <!—— 按時間滾動產生日誌檔案 ——> <!——滾動策略,按照時間滾動 TimeBasedRollingPolicy——> D:/logs/test。%d{yyyy-MM-dd}。log <!—— 只保留近七天的日誌 ——> 7 <!—— 用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌 ——> 1GB [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n <!—— 按時間和檔案大小滾動產生日誌檔案 ——> D:/logs/test。%d{yyyy-MM-dd}。%i。log <!—— 單個檔案的最大記憶體 ——> 100MB <!—— 只保留近七天的日誌 ——> 7 <!—— 用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌 ——> 1GB [Eran]%date [%thread %line] %level >> %msg >> %logger{10}%n <!—— 只處理INFO級別以及之上的日誌 ——> INFO <!—— 只處理INFO級別的日誌 ——> INFO ACCEPT DENY <!—— 非同步寫入日誌 ——> <!—— 不丟失日誌。預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 ——> 0 <!—— 更改預設的佇列的深度,該值會影響效能。預設值為256 ——> 512 <!—— 新增附加的appender,最多隻能新增一個 ——> <!—— 指定com。demo包下的日誌列印級別為DEBUG,但是由於沒有引用appender,所以該logger不會列印日誌資訊,日誌資訊向上傳遞 ——> <!—— 這裡的logger根據需要自己靈活配置 ,我這裡只是給出一個demo——> <!—— 指定開發環境基礎的日誌輸出級別為DEBUG,並且綁定了名為STDOUT的appender,表示將日誌資訊輸出到控制檯 ——> <!—— 指定生產環境基礎的日誌輸出級別為INFO,並且綁定了名為ASYNC的appender,表示將日誌資訊非同步輸出到檔案 ——>

程式碼中使用

終於到最後一步了,上邊介紹了怎麼配置logback-spring。xml配置檔案,下面介紹怎麼在專案中引入日誌物件,以及怎麼使用它輸出日誌,直接上程式碼:

package com。example。demo。controller;import org。slf4j。Logger;import org。slf4j。LoggerFactory;import org。springframework。web。bind。annotation。RequestMapping;import org。springframework。web。bind。annotation。RequestMethod;import org。springframework。web。bind。annotation。RestController;@RestControllerpublic class TestLog { private final static Logger log = LoggerFactory。getLogger(TestLog。class); @RequestMapping(value=“/log”,method=RequestMethod。GET) public void testLog() { log。trace(“trace級別的日誌”); log。debug(“debug級別日誌”); log。info(“info級別日誌”); log。warn(“warn級別的日誌”); log。error(“error級別日誌”); }}

在每一個需要使用日誌物件的方法裡邊都要定義一次private final static Logger log = LoggerFactory。getLogger(xxx。class);其中xxx代指當前類名,如果覺得這樣很麻煩,也可以透過@Slf4j註解的方式注入,但是這種方式需要新增pom依賴並且需要安裝lombok外掛,這裡就不概述了,需要了解的朋友可以自己google。

相關文章

頂部