1. 程式人生 > >日誌記錄的作用和方法 java

日誌記錄的作用和方法 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);
       }