1. 程式人生 > >java後端開發常用日誌技巧

java後端開發常用日誌技巧

經過不斷的專案實踐,不斷總結,一個好的開發人員,應該有個好的開發習慣,日誌是開發過程中不可缺少的一項,有了日誌可以節省很多我們不必要的麻煩,也可以使我們迅速的定位問題。

使用Logging框架寫Log基本上就三個步驟
  1. 引入loggerg類和logger工廠類
  2. 宣告logger
  3. 記錄日誌
例子:

//1. 引入slf4j介面的Logger和LoggerFactoryimport org.slf4j.Logger;
import org.slf4j.LoggerFactory;

publicclass UserService {
  //2. 宣告一個Logger,這個是static的方式,我比較習慣這麼寫。

  privatefinalstatic Logger logger = LoggerFactory.getLogger(UserService.class);

  publicboolean verifyLoginInfo(String userName, String password) {
    //3. log it,輸出的log資訊將會是:"Start to verify User [Justfly]
    logger.info("Start to verify User [{}]", userName);
returnfalse;
  }
}

學習連結:

兩種方式的優劣概述如下:
  • 靜態Logger物件相對來說更符合語義,節省CPU,節省記憶體,不支援注入
  • 物件變數Logger支援注入,對於一個JVM中執行的多個引用了同一個類庫的應用程式,可以在不同的應用程式中對同個類的Logger進行不同的配置。比如Tomcat上部署了倆個應用,他們都引用了同一個lib
通常為了程式碼的規範,判斷日誌Logger是否開啟使用如下方法
  • public boolean isTraceEnabled();
  • public boolean isDebugEnabled();
  • public boolean isInfoEnabled();
  • public boolean isWarnEnabled();
  • public boolean isErrorEnabled();
如: 這組方法的作用主要是避免沒必要的log資訊物件的產生,尤其是對於不支援引數化資訊的Log框架(Log4j 1, commons-logging)。如下面的例子所示,如果沒有加debug級別判斷,在Debug級別被禁用的環境(生產環境)中,第二行的程式碼將沒有必要的產生多個String物件。

1if(logger.isDebugEnabled()){
2   logger.debug("["+resultCount+"]/["+totalCount+"] of users are returned");
3 }

3. Log什麼

前面講了怎麼使用Loggger的方法log日誌,下面繼續講講在什麼地方需要記錄什麼級別的log,以及需要記錄什麼內容。

3.1 如何使用不同級別的Log

SLF4J把Log分成了Error,Warn,Info,Debug和Trace五個級別。我們可以把這倆個級別分成兩組

3.1.1 使用者級別

Error、Warn和Info這三個級別的Log會出現在生產環境上,他們必須是運維人員能閱讀明白的

3.1.1.1 Error

  • 影響到程式正常執行、當前請求正常執行的異常情況,例如:
    • 開啟配置檔案失敗
    • 第三方應用網路連線異常
    • SQLException
  • 不應該出現的情況,例如:
    • 某個Service方法返回的List裡面應該有元素的時候缺獲得一個空List
    • 做字元轉換的時候居然報錯說沒有GBK字符集

3.1.1.2 Warn

  • 不應該出現但是不影響程式、當前請求正常執行的異常情況,例如:
    • 有容錯機制的時候出現的錯誤情況
    • 找不到配置檔案,但是系統能自動建立配置檔案
  • 即將接近臨界值的時候,例如:
    • 快取池佔用達到警告線

3.1.1.3 Info

  • 系統執行資訊
    • Service方法的出入口
    • 主要邏輯中的分步驟
  • 外部介面部分
    • 客戶端請求引數和返回給客戶端的結果
    • 呼叫第三方時的呼叫引數和呼叫結果
在一些Exception處理機制中,我們會每層或者每個Service對應一個RuntimeException類,並把他們丟擲去,留給最外層的異常處理層處理。典型程式碼如下:
try{

}catch(Exception ex){
  String errorMessage=String.format("Error while reading information of user [%s]",userName);
  logger.error(errorMessage,ex);
thrownew UserServiceException(errorMessage,ex);
}

最後為了避免日誌過於繁瑣,開發者應該注意在專案中日誌的列印,簡單一句話,記錄有利於定位問題的日誌,做到不多打,也不少打同時根據需求調節日誌的級別,一般建議到info級別。