使用 Spring Boot 配置日誌

前言

當你使用 Spring Boot 啟動時,因為包含了 spring-boot-starter-logging ,讓 Logback 為 Spring Boot 提供開箱即用的日誌回溯——即提供日誌記錄,而不需要任何配置,並可以根據需求進行更改。

提供自己的配置有兩種方法:如果只需要簡單的更改,可以將它們添加到屬性文件中,例如 application。如果是要更改屬性或更復雜的需求,可以使用 XML 或 Groovy 來指定設置。

在本教程中,我們將專注於使用 XML 定義自定義日誌記錄配置,並查看一些基本操作,以及簡要介紹使用屬性文件來指定 Spring Boot 提供的標準配置以及關於它的一些簡單更改。

正文

前面我提到使用 spring-boot-starter 這個 dependency 來引入 spring-boot-start-logging ,參照如下代碼。

org.springframework.boot

spring-boot-starter

這將充分利用從屬於 dependencies 的 spring-boot-starter-logging 。

ch.qos.logback

logback-classic

org.slf4j

jul-to-slf4j

org.slf4j

log4j-over-slf4j

logback-classic 包含 dependency”logback-core“,且它們之間包含著手時所需要的一切。Spring Boot logging guide 提到基於 jcl-over-slf4j 的 dependency ,但是在 2.0.0.M3 版本中使用 spring-boot-starter-parent 時找不到它,所以我猜想有人在某處移除了這個 dependency 。 但是如果您正在使用當前 1.5.6.RELEASE 版本,它確實是存在的。

在開始具體配置 Logback 各個配置項之前,先簡單瞭解一下如何在一個類裡面記錄日誌信息。

@Service public class MyServiceImpl implements MyService {

private static final Logger LOGGER = LoggerFactory.getLogger(MyServiceImpl.class);

@Override public void doStuff(final String value) {

LOGGER.trace("doStuff needed more information - {}", value);

LOGGER.debug("doStuff needed to debug - {}", value);

LOGGER.info("doStuff took input - {}", value);

LOGGER.warn("doStuff needed to warn - {}", value);

LOGGER.error("doStuff encountered an error with value - {}", value);

}

}

LOGGER 使用不同的日誌記錄級別來記錄日誌信息 `trace`,`debug`,`info`,`warn`,`error`, 不同的級別對應相應的方法名,括號內為要記錄的具體日誌信息,也就是要傳入的參數。

下面用一個相對簡單的例子來熟悉一下 Logback 配置文件的配置項。Logback 會尋找項目中特定文件來配置 Logback 日誌記錄的設置,一般這個文件我們會命名為 logback.xml。

%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n

它將創建一個 ConsoleAppender 類的 appender ,它會將日誌消息輸出到控制檯,就像 System.out.print 一樣。設置日誌消息將遵循的模式,其中提供一些符號,這些符號根據已發送到記錄器的消息來替換生成的值。示例中已經包含了一些符號。以下是對每項符號的解釋:

  • %d - 以 SimpleDateFormat 允許的格式輸出日誌消息發生的時間。
  • %thread - 輸出日誌消息發生的線程的名稱。
  • $ -5level - 輸出日誌消息的日誌級別。
  • %logger {36} - 輸出日誌消息發生的包+類名。括號中的數字表示包+類名的最大長度。如果輸出長於指定的長度,則從根包中開始,每個包的第一個字符的子串將從根包開始直到輸出低於最大長度。類名永遠不會減少。轉換文字文檔中可以找到一個很好的案例。
  • %M - 輸出日誌消息發生的方法的名稱(使用起來很慢,不推薦,除非你不擔心性能,或者方法名稱對你尤其重要)。
  • %msg - 輸出實際的日誌消息。
  • %n - 換行。
  • %magenta() - 將括號中包含的輸出的顏色設置為品紅色(其他顏色也可用)。
  • highlight() - 根據記錄級別(例如ERROR = red)設置括號中包含的輸出的顏色高亮。

之前創建的 appender 是在根 logger 中引用的。在上述示例中,日誌記錄級別已設置為 INFO(可以使用小寫或大寫)。使系統僅輸出日誌級別在 INFO 或更高(INFO,WARN,ERROR)上定義的消息。

Logback 中的可用日誌記錄級別為:

  • OFF (不輸出日誌)
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE

回到上面已經展示的使用日誌級別為 INFO 的代碼段,其中只有級別在 INFO 或更高( WARN 和 ERROR )的消息才會輸出到日誌中。因此,如果我們調用 MyService.doStuff(“value”),它將輸出以下內容(與 Spring 相關的日誌均已從當前和後續示例中刪除)。

8-08-2017 13:32:18.549 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value

28-08-2017 13:32:18.549 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value

28-08-2017 13:32:18.549 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

請注意,即使 TRACE 和 DEBUG 級別的消息被髮送到 logger ,但它們並沒有被顯示是因為它們的級別低於 INFO 級別。

假如你希望寫成和前面的 application.properties 一樣效果的的代碼例子,你可以如下操作。

logging.level.root=info

logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n

當以這種形式完成時,logback.xml 文件是不要求的,同時可以看出,這種配置對於簡單設定更加簡短實用。

當你使用 Spring Boot ,添加自己的 logback.xml 時,LogBack 的默認配置將會被覆蓋。假如你希望包含 Spring Boot 的配置,你可以在標籤內添加如下內容。

假如你希望為某些類以不同於根級別的消息類型來記錄日誌消息,你可以為此類定義自己的日誌。這樣將允許你為特別的類設定日誌級別,就像為這個類定製了一些其他屬性。下面是你如何為單獨的一個類定義日誌。

假如你繼續運行代碼片段,並且根日誌已經定義,它將產生輸出:

27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value

27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value

27-08-2017 17:02:10.248 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value

27-08-2017 17:02:10.248 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value

27-08-2017 17:02:10.248 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value

27-08-2017 17:02:10.248 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value

27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

可以看到,每個日誌生產了兩次,這或許並不是你希望的。修復這個需要設定 additivity="false" 。如果不設定 additivity="false" ,由於根日誌附加器和類級別附加器都寫入日誌文件,就會導致消息被輸出兩次。即使根級別是 ERROR ,類級別設定為 DEBUG ,對於 MyServiceImpl 類,它將全局覆蓋它,導致根日誌附加器為 DEBUG 級別。下面是包含此屬性的代碼,看起來應該像這樣:

另外一種可能的解決方案是隻對類設置日誌級別,並不寫入日誌(由於沒用定義附加器)。這和上面的版本是等同的,但它使用了另外一個日誌附加器(這裡是根附加器)為它寫入日誌使之運行:

假如兩者中的任何一個解決方案被使用,返回的輸出都是所期望的。

27-08-2017 16:30:47.818 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value

27-08-2017 16:30:47.834 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value

27-08-2017 16:30:47.834 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value

27-08-2017 16:30:47.834 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

類級別的日誌可以在 application.properties 文件中添加以下內容。

logging.level.com.lankydan.service.MyServiceImpl=debug

包級別的日誌也可以簡單地使用包名替代類名在日誌標籤中進行定義。

通過將日誌記錄添加到其中一個 springframework 包,然後再轉移到其中一個類可以找到更多的證明。例如:

比較:

它打印出一個完整的不同的日誌行數字。可能是數百而不是一行或兩行,SpringApplication 的日誌包含在 org.springframework.boot 日誌中。

application.properties 中包級別的日誌遵循同一種格式只是用包名替換類名。

logging.level.com.lankydan.service=debug

當您需要標記要記錄的日誌的輸出文件夾時,可以通過配置文件重新定義屬性,這是很方便的。

這是屬性名為 LOG_PATH 的作用示例,並將使用目錄 DEV_HOME / logs ,其中 DEV_HOME 是項目的根目錄(至少我的是)。這可能不是將日誌保存到現實中的最佳位置,但是對於本教程的需求,它是適合的。 LOG_PATH 是對默認的 Spring boot 日誌記錄設置非常重要的屬性,還可以創建任何名稱的屬性。在整個配置的其餘部分訪問 LOG_PATH 的值,可以通過添加 $ {LOG_PATH} 來訪問。

此配置還可以通過 application.properties 實現,因為 LOG_PATH 在 Spring Boot 中非常重要性。

logging.path=logs

當您定義自己的屬性/變量時,也可以在其餘的地方引用它。例如:

propertyA=value

propertyB=${propertyA} # extra configuration if required

$ {propertyA} 將被 propertyA 的值替換,從而允許 propertyB 使用它。

使用 FileAppender 能夠將日誌保存到文件中。這是一個簡單的日誌追加程序,並將所有的日誌保存到一個單一的文件,但是這樣做可能會讓文件變得非常大,所以你更有需要使用 RollingFileAppender 來進行切割,稍後我們再來看看。

${LOG_PATH}/log.log

%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

這裡沒有太多配置。它與 ConsoleAppender 具有相同的結構,並添加了將日誌消息保存到的文件。值得注意的是,我刪除了在保存到文件時添加到編碼器日誌高亮配置,因為它將包含不想顯示的字符,並且會使日誌文件變得混亂。然後可以使用與前面顯示的 STDOUT appender 相同的方法來引用這個 appender 。正如下面的代碼引用片段:

繼之前的設置了 logging.path 的 application.properties 配置片段,如果沒有其他配置,會導致將日誌輸出到文件(以及控制檯)。因此,您可以按那樣做,但這樣也會導致寫入的文件和文件名不受您的控制。下面的示例將演示與上述 SAVE-TO-FILE appender 類似的配置。

logging.pattern.console=

logging.path=logs

logging.file=${logging.path}/log.log

logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

這和 XML 配置有所不同的是,該示例展示了在 MyServiceImpl 的日誌記錄器中引用的 appender ,但上述的 application.properties 代碼片段還包括將所有日誌消息輸出到文件的根日誌記錄器。logging.pattern.console 被添加來阻止輸出日誌到控制檯,以使其與上述的 XML 配置保持一致(這似乎不是一個很好的方式,但是我還沒有看到另一個更好的解決方案)。

RollingFileAppender 將根據日誌滾動策略將日誌保存到不同的文件。它允許將日誌輸出分割成您可以控制的各種形式,這樣做會方便很多。例如,您可以根據日期分隔日誌文件,以便查看過去在特定日期發生的錯誤。您可以根據文件大小或按照日期和大小組合進行分割,而無需在大量長期的文件中進行搜索。

TimeBasedRollingPolicy 將根據日期創建一個新的文件。以下配置將每天創建一個新文件,並使用 %d 符號將日期附加到日誌文件的名稱上。 %d 符號的格式很重要,因為要根據它來推斷日誌滾動的時間段。下面的示例是每天滾動,如果要每月滾動,可以使用 %d {MM-yyyy} 模式來包含日期部分。只要 %d 符號中的格式符合 SimpleDateFormat 類允許的格式,就可以使用不同的日誌滾動週期 - 不侷限於每天或每月。

${LOG_PATH}/log.log

%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

${LOG_PATH}/archived/log_%d{dd-MM-yyyy}.log

10

100MB

我已經在上面的例子中包含了 TimeBasedRollingPolicy 可用的一些屬性。maxHistory 用於設置歸檔日誌文件在被自動刪除之前將被保留多久。保留的時間取決於文件名中指定的迴轉時間,因此在上述示例中,迴轉週期為一天,允許在刪除之前存儲最多 10 天的歸檔日誌。 totalSizeCap 用於限制所有歸檔日誌文件的最大大小。它需要使用 maxHistory 鎖設置的 maxHistory 屬性,在刪除歸檔文件時優先級高於 totalSizeCap 。

此配置超出了在 application.properties 文件內就可以完成的範圍。對於以下示例也可以這樣說,儘管默認配置將允許日誌文件在達到 10 MB時進行迴轉,並支持最多 7 個歸檔日誌文件。

為了使滾動僅依賴與文件大小,需要使用 FixedWindowRollingPolicy 的滾動策略和 SizeBasedTriggeringPolicy 的觸發策略。 在上一個示例中,日誌在滾動時保存到歸檔文件夾,但是對於此策略,我並沒有保存它們,因為較小的文件大小使得分離的日誌更容易遍歷。

${LOG_PATH}/log.log

%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

${LOG_PATH}/log_%i.log

2

3

1KB

在 FixedWindowRollingPolicy 中找到的 minIndex 和 maxIndex 的可選屬性指定了在日誌文件名中可以使用的%i的最小值和最大值。 因此,在上述示例中,當日志滾動時,它們可以使用名稱 log_2.log 和 log_3.log (儘管從2開始是奇怪的,僅為了清楚而被包括。通常從1開始)。 生成日誌文件的過程如下(以上述代碼片段為例):

  • log.log 文件達到最大文件大小時--> log.log 重命名為 log_2.log 並新生成一個 log.log 文件
  • log_2.log 文件達到最大文件大小時-->log_2.log 重命名為 log_3.log, log.log 重命名為 log_2.log 並生成一個新的 log.log 文件
  • log_3.log 文件達到最大文件大小時-->log_3.log 刪除,log_2.log 重命名為 log_3.log,log.log 重命名為 log_2.log 並新生成一個 log.log 文件

SizeAndTimeBasedRollingPolicy 作為上述兩個示例的一部分,允許它在大小和時間上回滾。請注意,它使用 %d 和 %i 符號將日期和日誌號分別包含在文件名中。

${LOG_PATH}/log.log

%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

${LOG_PATH}/archived/log_%d{dd-MM-yyyy}_%i.log

10MB

10

100MB

如你所看到的,它包含 maxFileSize、maxHistory 和 totalSizeCap ,可以控制單個文件以及文件集合的大小。因此,上述示例將把 10 天的歷史記錄分割為 10MB 的文件,當所有文件的總大小達到 100MB 時,最舊的文件將被刪除。

現在我們已經看過如何定義可以輸出到控制檯或文件的多個 appender ,我們可以將它們組合一次輸出到兩種格式,只需在 logger 中引用多個 appender 即可:

所以現在這個 logger 將輸出到控制檯,使用 STDOUT 以及 SAVE-TO-FILE appender 輸出到文件。

可以通過 application.properties 實現類似的配置。如果你回到該頁面,你可能可以弄清楚自己要如何配置,因為上一個例子有一個額外添加的行,以阻止它輸出到控制檯和文件中。同樣,這將包含來自根 logger 的日誌消息,而不僅僅像 MyServiceImpl 上面的代碼段一樣。

logging.path=logs

logging.file=${logging.path}/log.log

logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

在使用 Logback 時,Spring Boot 提供的一個有用功能是在不同環境之間隔離配置的能力。 因此,你要在開發環境中需要保存到文件並打印到控制檯,但只能在生產中打印到文件,那麼這可以輕鬆實現。

要使其正常工作的第一步是將 logback.xml 文件重命名為 logback-spring.xml ,以便使用 springProfile 標籤。在此標籤中會提供一個名字,可以通過屬性、環境變量或 VM 選項設置。以下是如何將 springProfile 名稱設置為已被用於表示開發環境的 dev 。

在 application.properties 設置或作為環境變量設置:

spring.profiles.active=dev

或作為 VM 選項設置:

-Dspring.profiles.active=dev

現在當應用程序運行時,將使用用於 dev 的 springProfile,導使日誌輸出到控制檯和文件。如果這被推送到生產環境中,則該屬性需要設置為 prod,這會將配置匹配合適的位置,例如僅將日誌寫入文件,並可能更改所有或某些類/包的日誌記錄級別。

也可以通過 application.properties 來提供類似的配置。那麼,實際上並不是 application.properties,而是 application-dev.properties 和 application-prod.properties - 每個環境的單獨的配置文件。遵循 aapplication-{environment}.properties 的命名約定,其中 {environment} 替換為環境名稱。根據您的 VM 選項或環境變量,可以選擇其中一個,就像通過 logback-spring.xml 中的 springProfile 配置一樣。以下是上面描述片段的等效配置。

application-dev.properties:

logging.level.root=info

logging.level.com.lankydan.service=debug

logging.path=logs

logging.file=${logging.path}/log.log

logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n

application-prod.properties:

logging.level.root=info

logging.level.com.lankydan.service=error

logging.path=logs

logging.file=${logging.path}/log.log

logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

logging.pattern.console=

本文出自網上,由於頭條不能轉鏈接所以如果作者看到,請聯繫我

我想我應該把這篇文章發佈出來,雖然篇幅比我預想中的還要長。此外,還有很多可以使用 Logback 和 Spring Boot 來完成的工作,我在這裡並沒有涉及到。從本教程總結來看,你應該已經掌握瞭如何使用 Spring Boot 中的 Logback ,包括如何使用屬性文件來更改 Spring Boot 所提供的默認設置,以及如何進一步使用 Logback(通過 logback.xml 和 logback-spring.xml )創建自定義配置 。你還應該瞭解了屬性文件所提供的配置中的限制,以便你知道何時可以直接切換到使用 Logback 來實現你的目標。


分享到:


相關文章: