Like Share Discussion Bookmark Smile

J.J. Huang   2020-05-10   Java   瀏覽次數:

《阿里Java開發手冊》 | 異常日誌 - 日誌規約

【強制】應用中不可直接使用日誌系統(Log4j、Logback)中的 API ,而應依賴使用日誌框架(SLF4J、JCL–Jakarta Commons Logging)中的 API ,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。
說明:日誌框架(SLF4J、JCL–Jakarta Commons Logging)的使用方式(推薦使用 SLF4J)
使用 SLF4J:

1
2
3
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Test.class);

使用 JCL:

1
2
3
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private static final Log log = LogFactory.getLog(Test.class);

【強制】所有日誌文件至少保存15天,因為有些異常具備以“週”為頻次發生的特點。對於當天日誌,以“應用名.log”來保存,保存在/home/admin/應用名/logs/目錄下,過往日誌格式為:{logname}.log.{保存日期},日期格式:yyyy-MM-dd
說明:以 mppserver 應用為例,日誌保存在/home/admin/mppserver/logs/mppserver.log,歷史日誌 名稱為 mppserver.log.2016-08-01


【強制】應用中的擴展日誌(如打點、臨時監控、訪問日誌等)命名方式:
appName_logType_logName.log。logType:日誌類型,如 stats/monitor/access 等;logName:日誌描述。這種命名的好處:通過文件名就可知道日誌文件屬於什麼應用,什麼類型,什麼目的,也有利於歸類查找。
說明:推薦對日誌進行分類,如將錯誤日誌和業務日誌分開存放,便於開發人員查看,也便於通過日誌對系統進行及時監控。
正例:mppserver 應用中單獨監控時區轉換異常,如:mppserver_monitor_timeZoneConvert.log


【強制】在日誌輸出時,字符串變數之間的拼接使用佔位符的方式。
說明:因為 String 字符串的拼接會使用 StringBuilder 的 append()方式,有一定的性能損耗。使用佔位符僅 是替換動作,可以有效提升性能。
正例:

1
logger.debug("Processing trade with id: {} and symbol: {}", id, symbol);

【強制】對於 trace/debug/info 級別的日誌輸出,必須進行日誌級別的開關判斷。
說明:雖然在 debug(參數)的方法體內第一行程式碼 isDisabled(Level.DEBUG_INT) 為真時(Slf4j 的常見實作 Log4j 和 Logback),就直接 return,但是參數可能會進行字符串拼接運算。此外,如果 debug(getName())
這種參數內有 getName() 方法調用,無謂浪費方法調用的開銷。
正例:

1
2
3
4
// 如果判斷為真,那麼可以輸出 trace 和 debug 級別的日誌
if (logger.isDebugEnabled()) {
logger.debug("Current ID is: {} and name is: {}", id, getName());
}

【強制】避免重複打印日誌,浪費磁盤空間,務必在 log4j.xml 中設置 additivity=false。
正例:

1
<logger name="com.taobao.dubbo.config" additivity="false">

【強制】生產環境禁止直接使用 System.out 或 System.err 輸出日誌或使用 e.printStackTrace() 打印異常堆棧。
說明:標準日誌輸出與標準錯誤輸出文件每次 Jboss 重啟時才滾動,如果大量輸出送往這兩個文件,容易造成文件大小超過操作系統大小限制。


【強制】異常訊息應該包括兩類訊息:案發現場訊息和異常堆棧訊息。如果不處理,那麼通過關鍵字 throws 往上拋出。
正例:logger.error(各類參數或者對象 toString() + “_” + e.getMessage(), e);


【強制】日誌打印時禁止直接用 JSON 工具將對象轉換成 String。
說明:如果對象裡某些 get 方法被重寫,存在拋出異常的情況,則可能會因為打印日誌而影響正常業務流程的執行。
正例:打印日誌時僅打印出業務相關屬性值或者調用其對象的 toString() 方法。


【推薦】謹慎地記錄日誌。生產環境禁止輸出 debug 日誌;有選擇地輸出 info 日誌;如果使用 warn 來記錄剛上線時的業務行為訊息,一定要注意日誌輸出量的問題,避免把伺服器磁盤撐爆,並記得及時刪除這些觀察日誌。
說明:大量地輸出無效日誌,不利於系統性能提升,也不利於快速定位錯誤點。記錄日誌時請思考:

  • 這些日誌真的有人看嗎?
  • 看到這條日誌你能做什麼?
  • 能不能給問題排查帶來好處?

【推薦】可以使用 warn 日誌級別來記錄用戶輸入參數錯誤的情況,避免用戶投訴時,無所適從。如非必要,請不要在此場景打出 error 級別,避免頻繁報警。
說明:注意日誌輸出的級別,error 級別只記錄系統邏輯出錯、異常或者重要的錯誤訊息。


【推薦】盡量用英文來描述日誌錯誤訊息,如果日誌中的錯誤訊息用英文描述不清楚的話使用中文描述即可,否則容易產生歧義。
說明:國際化團隊或海外部署的伺服器由於字符集問題,使用全英文來註解和描述日誌錯誤訊息。


心得

看完這篇「日誌規約」後,歸類幾個重點,「是否需要?」、「紀錄層級、歸類」;另外一點要提出來,在寫日誌的時候,有時用到方法,要小心該方法是否被重寫,避免發生其他問題。

結語

文章越看越多,技術越學越多,就會發現自己的不足;技術學到後面都會想要將基礎再重新在打得更加扎實。

以前在開發覺得理所當然的事情,例如:命名規則、命名規範,照著別人怎麼說就怎麼做的想法,並沒有好好去想為什麼要這樣設計和規範。
於是乎同事們推薦《阿里巴巴Java開發手冊》來做閱讀,書中提到種種規範《正確範例》、《錯誤範例》還有解釋定義說明;我相信在閱讀完這一系列後,一定會更加扎實且實在。

如對此書有興趣,建議去購買官方認證的書籍,給予官方支持。

註:如有侵權,通知即刪。


註:以上參考了
Alibaba-Java-Coding-Guidelines Github
Alibaba-Java-Coding-Guidelines English Version