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