日誌實踐推薦

背景


軟件系統生產穩定,依靠着各類高可用、高吞吐、高性能的設計。一旦出現生產問題,經常須要線上定位問題。java

日誌則是必備的,問題定位利器。經常出現線上問題,咱們均可以經過日誌精肯定位。同時在開發過程當中,因爲極長的調用鏈難以快速定位問題或難以復現時,它是極好的利器。linux

日誌級別


一個項目各個log級別的定義應該是清楚明確的,是每一個開發人員所遵循的;數據庫

即便是TRACE或者DEBUG級別的日誌,也應該有必定的規範,要保證除了開發人員本身之外,包括測試人員和運維人員均可以方便地經過日誌定位問題;bash

FATAL

表示須要當即被處理的系統級錯誤。服務器

當該錯誤發生時,表示服務已經出現了某種程度的不可用,系統管理員須要當即介入。網絡

這屬於最嚴重的日誌級別,所以該日誌級 別必須慎用,若是這種級別的日誌常常出現,則該日誌也失去了意義。app

一般狀況下,一個進程的生命週期中應該只記錄一次FATAL級別的日誌,即該進程遇到無 法恢復的錯誤而退出時。運維

固然,若是某個系統的子系統遇到了不可恢復的錯誤,那該子系統的調用方也能夠記入FATAL級別日誌,以便經過日誌報警提醒系統管 理員修復;ide

ERROR

該級別的錯誤也須要立刻被處理,可是緊急程度要低於FATAL級別。函數

當ERROR錯誤發生時,已經影響了用戶的正常訪問。從該意義上來講,實際上 ERROR錯誤和FATAL錯誤對用戶的影響是至關的。

FATAL至關於服務已經掛了,而ERROR至關於好死不如賴活着,然而活着卻沒法提供正常的服務,只能不斷地打印ERROR日誌。

特別須要注意的是,ERROR和FATAL都屬於服務器本身的異常,是須要立刻獲得人工介入並處理的。

而對於用戶本身 操做不當,如請求參數錯誤等等,是絕對不該該記爲ERROR日誌的;

WARN

該日誌表示系統可能出現問題,也可能沒有,這種狀況如網絡的波動等。

對於那些目前還不是錯誤,然而不及時處理也會變爲錯誤的狀況,也能夠記爲WARN日 志,例如一個存儲系統的磁盤使用量超過閥值,或者系統中某個用戶的存儲配額快用完等等。

對於WARN級別的日誌,雖然不須要系統管理員立刻處理,也是須要 即便查看並處理的。

所以此種級別的日誌也不該太多,能不打WARN級別的日誌,就儘可能不要打;

INFO

該種日誌記錄系統的正常運行狀態,例如某個子系統的初始化,某個請求的成功執行等等。

經過查看INFO級別的日誌,能夠很快地對系統中出現的 WARN,ERROR,FATAL錯誤進行定位。

INFO日誌不宜過多,一般狀況下,INFO級別的日誌應該不大於TRACE日誌的10%;

DEBUG or TRACE

這兩種日誌具體的規範應該由項目組本身定義,該級別日誌的主要做用是對系統每一步的運行狀態進行精確的記錄。

經過該種日誌,能夠查看某一個操做每一步的執 行過程,能夠準肯定位是何種操做,何種參數,何種順序致使了某種錯誤的發生。

能夠保證在不重現錯誤的狀況下,也能夠經過DEBUG(或TRACE)級別的 日誌對問題進行診斷。

須要注意的是,DEBUG日誌也須要規範日誌格式,應該保證除了記錄日誌的開發人員本身外,其餘的如運維,測試人員等也能夠經過 DEBUG(或TRACE)日誌來定位問題;

在出錯時,日誌中包含儘可能多的有用上下文信息


爲何能夠這麼作?

日誌過多你們夥會說影響性能,可是值得指出的是出錯是小几率分支。若是是出錯是大機率分支那,打日誌之外操做更會成爲瓶頸!

多打日誌減小支持時間,比起開發所用的實現時間,線上和線下的排查/支持要花費不少時間;

別吞噬異常!

抓住異常沒有書寫人和響應日誌,將致使難以定位。
     @Override
     public  UserAmountStat getUserYestodayStat(Long userId, String day)  throws  GlobalServiceException {
         // TODO Auto-generated method stub
         try  {
             UserAmountStat stat = userAmountStatMapper.getUserYestodayStat(userId, day);
             if  (stat ==  null ) {
                 stat =  new  UserAmountStat();
                 stat.setBet(0l);
                 stat.setPrize(0l);
                 stat.setBonus(0l);
             }
             return  stat;
         catch  (Exception e) {
             // TODO: handle exception
             throw  new  GlobalServiceException(e);
         }
     }

此處推薦的須要在日誌中記錄的內容

  • 在系統啓動或初始化時記錄重要的系統初始化參數
  • 記錄系統運行過程當中的全部的錯誤
  • 記錄系統運行過程當中的全部的警告
  • 在持久化數據修改時記錄修改前和修改後的值
  • 記錄系統各主要模塊之間的請求和響應
  • 重要的狀態變化(如對系統白名單的修改等)
  • 系統中一些長期執行的任務的執行進度
  • 服務信息:接口、方法、版本等等
  • 若是是超時,配置的超時時間,本次處理所用的時間,是Server端超時還Client超時?
  • 重試的次數,本次重試的是第幾回(fail over)

RequestID

將一個請求的整個處理流程和惟一的requestID關聯起來,requestID規則另行定義。

日誌輸出級別

在設置日誌輸出級別時,推薦以下:

  • 開發、測試環境打開DEBUG;
  • 線上生產環境保證設置爲WARN級別;

 

關於日誌分類


日誌從功能來講,可分爲診斷日誌、統計日誌、審計日誌。

診斷日誌:

  • 請求入口和出口
  • 外部服務調用和返回
  • 資源消耗操做: 打開文件等
  • 容錯行爲: 譬如雲硬盤的副本修復操做
  • 程序異常: 譬如數據庫沒法鏈接
  • 後臺操做:清理程序

  • 啓動、關閉、配置加載

  • 拋出異常時,不記錄日誌

統計日誌:

  • 用戶訪問統計
  • 計費日誌(如記錄用戶交易流水日誌,格式較爲嚴格,便於統計)

審計日誌:

  • 管理操做(相似於登陸信息記錄)

關於日誌格式


日誌格式必定要統一,不能任由開發人員的喜愛來。舉例來講,對於NOS視頻截圖超時的ERROR日誌,有如下幾種方式打印:

第一種:
logger.error(「Gearman timeout exception  for  request 」 + getRequestID() + 」 value: 」 + value, e);
第二種:
logger.error(「RequestID: 」 + getRequestID() + 「, Error Message: Gearman timeout exception: 」 + e);
第三種:
logger.error(getErrorMessage(getRequestID(), getErrorMessage(), e));

第一種方式打印日誌便是開發人員按照本身的喜愛來的,這種方法帶來的問題是:

  • 系統中日誌格式不統一,不利於自動化處理
  • 有些日誌可能只有開發人員本身才能看懂
  • 代碼規範性很差

而第三種方式,經過一個函數來規範日誌格式,全部開發人員即可以經過該接口實現統一的日誌。

關於日誌語義


日誌書寫語義必定要明確,定義明確語義的異常類信息,在此列舉linux環境下兩個報錯信息做爲示例;

[root @ip - 172 - 31 - 1 - 43  ~]# cd /file
-bash: cd: /file: 沒有那個文件或目錄
[root @ip - 172 - 31 - 1 - 43  ~]# cd build- public -ult_6. 0 - 2015 - 09 - 02 -17_6d3c3ee51a.tar.gz
-bash: cd: build- public -ult_6. 0 - 2015 - 09 - 02 -17_6d3c3ee51a.tar.gz: 不是目錄

咱們能夠看到一樣是cd命令,在遇到不一樣的錯誤行爲時,分別針對性的給出了報錯信息。

相關文章
相關標籤/搜索