小談日誌與其實踐

本文首發於泊浮目的專欄: https://segmentfault.com/blog...

前言

前陣子在論壇上看到一個問題,大體的意思就是日誌該怎麼打?或者說是,咱們應該在日誌中打印出哪些內容?java

看了該問題,筆者真是有所感慨:從實習到如今,從接的外包小項目到企業級應用,從以爲日誌沒什麼軟用到在客戶的環境中排bug在日誌中看到蛛絲馬跡。不得不說,日誌真是過重要了。segmentfault

什麼是日誌

日誌文件是用於記錄系統操做事件的記錄文件或文件集合,是一個軟件系統的重要組成部分。通常良好的日誌能夠幫助咱們:api

  • 瞭解項目的運行狀態
  • 發現潛在的性能問題
  • 快速定位故障所在
  • 價值化(大數據分析等)
  • .....

日誌的分類

就功能來講,咱們通常分爲診斷日誌、審計日誌、統計日誌。服務器

診斷日誌

通常診斷日誌包含的信息最爲全面,包括但不限於:網絡

  • Request && Response
  • 系統操做行爲:讀寫文件、定時任務等
  • 異常行爲:不可容錯與容錯行爲
  • 第三方服務的調用

審計日誌

記錄帳戶對資源的操做行爲。比起診斷日誌,可能更加方便普通人的閱讀,運營、運維同志們的福利。session

統計日誌

  • 用戶訪問統計:瀏覽、日活、IP、上傳下載的數據量
  • 計費日誌(常見於公有、私有云中)

日誌中該記錄什麼

先來看看一段ZStack中的日誌app

2017-09-04 13:37:45,509 TRACE [CloudBusImpl2] {} [msg send]: {"org.zstack.header.host.APIDeleteHostMsg":{"uuid":"e36525b2fbe9429093450b72a4552656","deleteMode":"Permissive","session":{"uuid":"a7c068a7d3fd41388994e4b413cf4f7d"},"timeout":-1,"headers":{"correlationId":"f1ad7d11a73f472ca5dc2ea003f16006","replyTo":"zstack.message.cloudbus.bbaaa63f1b4d4b0cb96e452bf68eaccf","noReply":"false","schema":{},"task-context":{}},"id":"f1ad7d11a73f472ca5dc2ea003f16006","serviceId":"api.portal","createdTime":1504417065507}}

咱們能夠看到精確的時間,以及日誌級別,日誌調用者及其行爲,以及參數。其中correlationId就是咱們常說的RequestID。運維

RequestID:咱們一般用RequestID來對請求進行惟一的標記,目的是能夠經過RequestID將一個請求在系統中的執行過程串聯起來,這在分佈式系統中的威力是巨大的。該RequestID一般會隨着響應返回給調用者,若是調用出現問題,調用者也能夠經過提供RequestID幫助服務提供者定位問題。以Java爲例,生成方法能夠考慮以下:
public static String getUuid() {
      return UUID.randomUUID().toString().replace("-", "");
}
ps:去掉-是爲了更方便的copy-paste。

這樣咱們即可以利用這個線索在日誌中快速的找出問題啦。同時,咱們也能夠根據本身的需求來放入時間戳、業務屬性等來組成RequestIDdom

除以前提到的該記錄的日誌分佈式

  • Request && Response
  • 系統操做行爲:讀寫文件、定時任務等
  • 異常行爲:不可容錯與容錯行爲(好比分佈式系統中的心跳機制,請記錄嘗試的次數)
  • 第三方服務的調用
  • 還有:

    • 不多出現的else狀況
    • 非預期執行
    • 批量插入操做記錄
    • 服務狀態變化(儘有可能記錄線索)

咱們也要去掉那些多餘的日誌,好比:

  • 明明能夠一條輸出卻多條輸出(不管從閱讀仍是性能上來看都不是較爲好的選擇)
  • 爲調試而添加的臨時日誌
  • 預期會被正常處理的異常,卻打出堆棧
  • 等...

關於日誌級別

咱們一般使用的日誌庫,將日誌基本分爲如下幾類(從高到低):

  • FATAL – The FATAL level designates very severe error events that will presumably lead the application to abort.
  • ERROR – The ERROR level designates error events that might still allow the application to continue running.
  • WARN – The WARN level designates potentially harmful situations.
  • INFO – The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
  • DEBUG – The DEBUG Level designates fine-grained informational events that are most useful to debug an application.
  • TRACE – The TRACE Level designates finer-grained informational events than the
參考帖子: https://stackoverflow.com/que...

對於日誌級別的分類,有如下參考:

FATAL

表示須要當即被處理的系統級錯誤。當該錯誤發生時,表示服務已經出現了某種程度的不可用,系統管理員須要當即介入。這屬於最嚴重的日誌級別,所以該日誌級別必須慎用,若是這種級別的日誌常常出現,則該日誌也失去了意義。一般狀況下,一個進程的生命週期中應該只記錄一次FATAL級別的日誌,即該進程遇到沒法恢復的錯誤而退出時。固然,若是某個系統的子系統遇到了不可恢復的錯誤,那該子系統的調用方也能夠記入FATAL級別日誌,以便經過日誌報警提醒系統管理員修復;

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)日誌來定位問題;

其餘

  • 注意制定規範,而不是讓開發者隨意打日誌。對於日誌的等級選擇也要注意。
  • 注意日誌的切片設置,以避免文件過大不方便操做。
  • 過時的日誌按期清理。
相關文章
相關標籤/搜索