by Anthony Vallone
Google Testing Blog
要找到一個系統問題的根本原因,你需要多長時間?5分鍾?還是5天?如果你的答案接近5分鍾,很大可能是因為你的生產環境和測試環境使用了非常好的日志記錄。更常見的情況是,諸如日志、異常處理、甚至測試這類非核心的工作,被當作一種出現問題后的補救方式。同異常處理和測試一樣,日志記錄真的也需要策略,無論是生產環境還是測試環境。永遠不要低估日志的作用。有了使用得當的日志,你甚至可以說debug不是必需的。下面是多年來對我非常有用的日志記錄指導原則。
保持適度
切勿記錄過多。大量的磁盤空間被日志占用說明你沒有想過應該記錄什么。如果記錄了太多,你就還需要設計出復雜的方法來減少磁盤訪問、保留歷史記錄、歸檔大量數據、以及在這些數據中查詢。最關鍵的是,你將發現在這么多垃圾中找到有用信息是多么的困難。
唯一一個比記錄過多日志還差的事是,記錄的過少。日志通常有兩個主要目的:定位問題和事件確認。如果你的日志不能明確一個bug的原因,或者某個事務是否執行,你就記錄的過少了。
適合記錄的:
- 重要啟動配置
- 錯誤
- 警告
- 持久性數據的更改
- 主要系統組件間的請求和響應
- 重要的狀態變化
- 用戶交互
- 有已知失敗風險的調用
- 較長時間的等待
- 長期運行任務的周期性進度
- 重要的邏輯分支和導向分支的條件
- 從高層方法來匯總處理流程的步驟和事件——避免在底層方法中記錄復雜流程的每一步驟
不適合記錄的:
- 方法入口——不要記錄方法入口,除非它非常重要或者是日志處於調試級別。
- 循環中的數據——避免在循環的多次迭代中記錄日志。如果是小循環,或者是間歇性的記錄,倒也無妨。
- 大消息或者文件的內容——截斷或者使用一些有利於調試的方式進行匯總。
- 良性錯誤——那些不是真正錯誤的錯誤會令日志的讀者感到困惑。當異常處理是執行成功的一部分時,有時會遇到這種情況。
- 重復的錯誤——不要重復的記錄相同或者相似的錯誤。這樣可能會快速的填滿日志,並且隱藏掉真正的問題。各種類型錯誤發生的頻率最好有監視器(monitor)處理。日志只需捕獲問題的詳細信息。
多個日志級別
不要把所有信息都記錄在同一個日志級別中。絕大多數的日志庫都提供多個級別,系統啟動時可以進行指定。這樣可以很方便的控制日志詳盡程度。
典型的級別有:
- 調試——最詳細,但是只有在開發或者調試時適用。
- 信息——最常用的級別。
- 警告——奇怪的或者不在預期之內的一些狀態,但是可接受。
- 錯誤——有錯誤發生,但是流程不受影響。
- 嚴重——流程無法繼續,系統將關閉或者重啟。
從實際使用來講,只需要兩種級別的日志配置:
- 生產環境——除了調試級別,其他全開。如果生產環境發生了問題,日志應該能夠指明原因。
- 開發和調試——編寫新代碼或是嘗試復現問題時,打開全部級別。
測試日志同樣重要
日志的質量對於測試代碼和產品代碼同樣重要。當一次測試運行失敗時,日志應當明確的指出這個錯誤是來自測試本身還是生產系統。如果做不到這一點,那么測試的日志是有問題的。
測試日志應該必需包括:
- 測試執行環境
- 初始狀態
- 准備步驟
- 用例步驟
- 與系統的交互
- 期望的結果
- 實際的結果
- 清理步驟
利用臨時日志隊列實現條件性的詳細信息控制
發生錯誤時,日志應當包含大量的詳細信息。但不幸的是,當遇到一個錯誤時,導致這個錯誤發生的詳細信息可能已經無法獲得了。如果你聽從了“不要記錄過多”的建議,在錯誤日志之前的那些日志可能無法提供足夠的細節。解決這個問題的一個好的方式是,在內存中創建臨時的日志隊列。在事務的處理過程中,將每一步的詳盡信息追加到隊列中。如果事務成功完成,丟棄這個隊列,只記錄一個匯總。如果發生了錯誤,就把錯誤和隊列里的全部內容記錄下來。這一方法對於系統交互的日志尤其有效。
問題是機遇
當生產環境出現問題時,你必將集中精力尋找並且修復問題,但是也不要忘記考慮一下日志。如果你費了很大力氣才找到問題的原因,這將是個非常好的機會來改善你的日志。修復問題前,先修復你的日志記錄,使其可以清楚的指明問題原因。如果這個問題又一次發生,將會很容易辨認。
如果無法復現問題,或者測試結果不確定,改進日志以便可以在問題再次發生時將其記錄下來。
在整個開發的生命周期內,都應該持續的利用問題來改進日志。寫新代碼時,試着少用debug,只使用日志。這些日志是否能夠說明發生了什么?如果不能,日志就是不充分的。
最好也記錄性能數據
記錄時間數據可以用來幫助定位性能問題。例如,要找到一個大型系統的超時原因是很困難的,除非你能夠追蹤每一個重要處理步驟的耗時情況。這是很容易做到的,只需記錄那些可能會比較耗時的調用的開始和結束時間即可:
- 重要的系統調用
- 網絡請求
- CPU密集運算
- 連接設備的交互
- 事務
在多線程和多進程中追蹤痕跡
在涉及到多線程或多進程的處理時,要為事務創建獨一的標識。事務初始化時創建ID,將它傳入每一個為此事務工作的部分。當記錄關於此事務的日志時,每一個部分都應該記錄下這個ID。這樣,在多個事務並行執行時,追蹤一個特定的事務會容易很多。
監控和日志相互完善
一個生產服務應該既有日志也有監控。監控提供了一種實時的對於系統狀態的統計匯總。它可以提醒你,是否一定比例的某個類型請求失敗了,是否系統正在經受不正常的流量訪問,性能是否在下降,或者其他的一些異常。在某些情況下,只是這些信息就可以為找到問題原因提供線索。不過,大多數情況下,監控警報只是為了簡單的觸發你的調查。監控將問題的症狀展現給我們。日志則針對各個事務提供了詳細的信息和狀態,這樣你才能全面的理解問題的原因。
