Java日誌記錄中很常見的五條規則
日誌記錄是在軟體開發過程中常常需要考慮的關鍵因素。當產品運行出錯時,記錄檔通常是我們進行錯誤分析的首要選擇。而且,在很多情況下,它們是我們手上唯一可以用來查明發生狀況和問題根本原因的資訊。可見,正確記錄需要的資訊是極其重要的。
以下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 Logging 和 SLFJ 更傾向於如下的等級:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。
日誌過濾等級則需要取決於代碼的開發階段:成品與仍處在測試、Integration Environment下的代碼日誌等級就不能相同。
更具體的來說,日誌等級也應該參考代碼的歸屬情況。
一般而言,我們自己的應用程式代碼應該比使用的任何第三方開發庫擁有更詳細的日誌記錄。
比如說,Apache 的通用調試訊息出現在我們的記錄檔中,就沒有多大意義。
我通常像這樣配置日誌記錄:
注意:個人而言,我不建議使用 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 的情況下才會被建立。