日誌記錄的作用和方法 java
程式中記錄日誌一般有兩個目的:Troubleshooting和顯示程式執行狀態。好的日誌記錄方式可以提供我們足夠多定位問題的依據。日誌記錄大家都會認為簡單,但如何通過日誌可以高效定位問題並不是簡單的事情。這裡列舉下面三個方面的內容,輔以程式碼示例,總結如何寫好日誌,希望對他人有所啟發和幫助:
- 怎樣記日誌可以方便Troubleshooting
- 程式執行狀態可以記哪些
- 應該避免怎樣的日誌方式
怎樣記日誌可以方便Troubleshooting?
1. 對外部的呼叫封裝
程式中對外部系統與模組的依賴呼叫前後都記下日誌,方便介面除錯。出問題時也可以很快理清是哪塊的問題
LOG.debug("Calling external system:" + parameters); Object result = null; try { result = callRemoteSystem(params); LOG.debug("Called successfully. result is " + result); } catch (Exception e) { LOG.warn("Failed at calling xxx system . exception : " + e); }
2.狀態變化
程式中重要的狀態資訊的變化應該記錄下來,方便查問題時還原現場,推斷程式執行過程
boolean isRunning;
isRunning = true;
LOG.info("System is running");
//...
isRunning = false;
LOG.info("System was interrupted by " + Thread.currentThread().getName());
3.系統入口與出口:
這個粒度可以是重要方法級或模組級。記錄它的輸入與輸出,方便定位
void execute(Object input) {
LOG.debug("Invoke parames : " + input);
Object result = null;
//business logic
LOG.debug("Method result : " + result);
}
4.業務異常:
任何業務異常都應該記下來:
try { //business logical } catch (IOException e) { LOG.warn("Description xxx" , e); } catch (BusinessException e) { LOG.warn("Let me know anything"); } catch (Exception e) { LOG.error("Description xxx", e); }
5.非預期執行:
為程式在“有可能”執行到的地方列印日誌。如果我想刪除一個檔案,結果返回成功。但事實上,那個檔案在你想刪除之前就不存在了。最終結果是一致的,但程式得讓我們知道這種情況,要查清為什麼檔案在刪除之前就已經不存在
int myValue = xxxx;
int absResult = Math.abs(myValue);
if (absResult < 0) {
LOG.info("Original int " + myValue + "has nagetive abs " + absResult);
}
6.很少出現的else情況:
else可能吞掉你的請求,或是賦予難以理解的最終結果
Object result = null;
if (running) {
result = xxx;
} else {
result = yyy;
LOG.debug("System does not running, we change the final result");
}
程式執行狀態可以記哪些?
程式在執行時就像一個機器人,我們可以從它的日誌看出它正在做什麼,是不是按預期的設計在做,所以這些正常的執行狀態是要有的。
1. 程式執行時間:
long startTime = System.currentTime();
// business logical
LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms");
2. 大批量資料的執行進度:
LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%");
3.關鍵變數及正在做哪些重要的事情:
執行關鍵的邏輯,做IO操作等等
String getJVMPid() {
String pid = "";
// Obtains JVM process ID
LOG.info("JVM pid is " + pid);
return pid;
}
void invokeRemoteMethod(Object params) {
LOG.info("Calling remote method : " + params);
//Calling remote server
}
應該避免怎樣的日誌方式?
1. 混淆資訊的Log
日誌應該是清晰準確的: 當看到日誌的時候,你知道是因為連線池取不到連線導致的問題麼?
Connection connection = ConnectionFactory.getConnection();
if (connection == null) {
LOG.warn("System initialized unsuccessfully");
}
2. 記錯位置
產品程式碼中,使用console記錄日誌,導致沒有找到日誌。
} catch (ConfigurationException e) {
e.printStackTrace();
}
3. 記錯級別
記錯級別常常發生,常見的如:混淆程式碼錯誤和使用者錯誤,如登入系統中,如果惡意登入,那系統內部會出現太多WARN,從而讓管理員誤以為是程式碼錯誤。可以反饋使用者以錯誤,但是不要記錄使用者錯誤的行為,除非想達到控制的目的。
LOG.warn("Failed to login by "+username+");
4. 遺漏資訊
這裡可能包含兩種情況:(1)使用者自己少寫了資訊,導致毫無參考價值;(2)使用者呼叫log的方式導致丟失資訊,如下例,沒有stack trace.
} catch (Exception ex) {
log.error(ex);
}