Java日誌記錄的5條規則

ImportNew發表於2015-12-30

日誌記錄是在軟體開發過程中常常需要考慮的關鍵因素。

當產品執行出錯時,日誌檔案通常是我們進行錯誤分析的首要選擇。

而且,在很多情況下,它們是我們手上唯一可以用來查明發生狀況和問題根本原因的資訊。

可見,正確記錄需要的資訊是極其重要的。

以下5條日誌規則,讓我們可以檢查和改進在程式碼中操作日誌記錄的方式。

同時也請注意,我們既不會討論怎麼配置一個日誌引擎,也不會相互比較。

規則1、日誌是面向讀者的

日誌訊息不僅要對書寫(日誌)程式碼的人有意義,也應該對日誌檔案的讀者有意義。

這似乎是一條很明顯但卻經常違背的規則。

ERROR: Save failure - SQLException .....

舉個例子吧,我們來看看下面這條日誌資訊:

ERROR: Save failure - SQLException .....

儲存什麼呢?這條訊息在開發者看來是能說明一些問題的,但是對於正在苦苦檢視產品問題的可憐傢伙來說,卻毫無用處。

RROR: Save failure- Entity=Person, Data=[id=123 surname="Mario"] - SQLException....

更合適的資訊是這樣的:

RROR: Save failure- Entity=Person, Data=[id=123 surname="Mario"] - SQLException....

這就解釋了你想要儲存的東西(這裡是一個 Person,是一個 JPA 實體)以及這個 Person 例項相關的內容。

請注意相關這個單詞,並不是指泛泛的全體:我們不應該讓無價值的資訊使日誌檔案變得亂糟糟,比如說完整列印所有的實體欄位。

通常,實體名字和其邏輯關鍵字足以識別在表格中的一條記錄了。

規則2、匹配日誌等級和執行環境

在 Java 系統中提供的所有日誌管理工具和引擎都有日誌等級(ERROR、INFO……)的概念,這將有可能過濾掉等級過低的訊息。

例如,Java util logging 使用如下的等級:SEVERE、WARN、INFO、FINE、FINER、FINEST(+ CONFIG 和 OFF)。相反,兩個最受歡迎的日誌管理工具, Apache Commons LoggingSLFJ 更傾向於如下的等級:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。

日誌過濾等級則需要取決於程式碼的開發階段:成品與仍處在測試、整合環境下的程式碼日誌等級就不能相同。

更具體的來說,日誌等級也應該參考程式碼的歸屬情況。

一般而言,我們自己的應用程式程式碼應該比使用的任何第三方開發庫擁有更詳細的日誌記錄。

比如說,Apache 的通用除錯訊息出現在我們的日誌檔案中,就沒有多大意義。

我通常像這樣配置日誌記錄:

  • 成品階段: 我的程式碼是 INFO 等級,第三方庫是 WARN。
  • 測試、整合階段:我的程式碼是 DEBUG 等級,第三方庫是 WARN(或者如果需要的話是 INFO)。
  • 開發階段:任何有意義的資訊。

注意:個人而言,我不建議使用 TRACE/FINEST 等級(我並不是唯一持這種觀點的人,可以參考 這裡 的例子)。

我並沒有發現 DEBUG 和 TRACE 有多大的區別,而年輕團隊的成員常常苦惱於到底是使用 DEBUG 還是 TRACE 。

根據 KISS 原則,我建議只使用 RROR、WARN、INFO 和 DEBUG 等級。

規則3、提交前去除編碼幫助日誌

編碼時,我們常常會使用 logger 或是 System.out 在程式碼中新增日誌訊息,來更好地掌握應用程式在執行、除錯期間發生的狀況。

void aMethod(String aParam) {
  LOGGER.debug(“Enter in aMethod”);
  if (“no”.equals(aParam)) {
  LOGGER.debug(“User says no”);
  ….

比如這樣的程式碼:

void aMethod(String aParam) {
  LOGGER.debug(“Enter in aMethod”);
  if (“no”.equals(aParam)) {
  LOGGER.debug(“User says no”);
  ….

這些訊息顯示被呼叫的方法並且備份內部變數及方法引數值,主要是為了追蹤應用程式的行為。這在非測試驅動開發中相當受歡迎。

但糟糕的是,一旦程式碼釋出(測試之後成為成品)這些訊息通常就無用武之地了。

所以,這條規則簡單來說就是:一旦你已經完成開發工作,在將程式碼提交到使用中的 SCM 系統(git、svn……)之前,要去除所有臨時的和不必要的日誌訊息。

這條規則並不是要求去除所有的 DEBUG 訊息,只是針對那些在應用程式完成和釋出後就沒有意義的訊息,或者是說當我們有理由相信應用程式能正確執行時就失去意義的那些訊息。

規則4、log DEBUG訊息之前檢查日誌等級

根據第2條規則,在產品日誌中,我們只會顯示 ERROR、WARN、INFO 等級的訊息,但是在程式碼中我們也可以使用一些不會影響產品執行的 DEBUG 訊息。

if ( LOGGER.isDebugEnabled((){
 LOGGER.debug (…….)
 }

每次你想要 log 一個 DEBUG 訊息時(在使用了規則3後的留下的所有訊息),需要在前面新增一個檢查來明確是否啟用了 DEBUG 日誌:

if ( LOGGER.isDebugEnabled((){
 LOGGER.debug (…….)
 }

這種做法可以阻止程式碼去建立日誌訊息和呼叫 logger,提高產品執行程式的效率。

規則5、瞭解你的 logger

我們使用 logger 方法的方式可能會帶來巨大的開銷:

  • 建立訊息字串
  • 組織包含在訊息字串中的資料

我們應該查閱所選擇的日誌管理工具、引擎的 javadoc 文件,瞭解使用它們 logger 的最有效的方法。

LOGGER.info(“Person name is “ + person.getName());

例如,我們可以建立一條這樣的訊息:

LOGGER.info(“Person name is “ + person.getName());

這就建立了不必要的字串例項。

LOGGER.info(“Person name is {}“, person.getName());

使用SLF4J,正確的用法應該是:

LOGGER.info(“Person name is {}“, person.getName());

這裡的格式化字串是常量,不可變訊息只有在允許 logging 的情況下才會被建立。

相關文章