Java日志规约
在日常的開發(fā)中,免不了會遇見Bug.如果系統(tǒng)有一份完善的日志,那么你與Bug交鋒,就是知己知彼,解決Bug自然會比較輕松。
相反,如果沒有一份完善的日志,那么與Bug交鋒,就是敵暗我明,最終只會被Bug整的心力交瘁,頭發(fā)稀疏。
所以,作為程序員,一定要把日志打印好。
寫好日志,不但是快速定位問題的好幫手,也是我們保護自己的好好利器。
為了更好的規(guī)范我們的日志,現(xiàn)在我們遵循阿里巴巴開發(fā)規(guī)范中的日志規(guī)約。
記錄日志時請思考:這些日志真的有人看嗎?看到這條日志你能做什么?能不能給問題排查帶來好處?
?
阿里規(guī)范
(SLF4J、JCL–Jakarta Commons Logging)中的 API,使用門面模式的日志框架,有利于維護和各個類的日志處理方式統(tǒng)一。
說明:日志框架(SLF4J、JCL–Jakarta Commons Logging)的使用方式(推薦使用 SLF4J)
使用 SLF4J
使用 JCL:
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; private static final Log log = LogFactory.getLog(Test.class);?
2. 在日志輸出時,字符串變量之間的拼接使用占位符的方式。
說明:因為 String 字符串的拼接會使用 StringBuilder 的 append()方式,有一定的性能損耗。使用占位符僅是替換動作,可以有效提升性能。
?
3. 避免重復打印日志,浪費磁盤空間,務(wù)必在日志配置文件中設(shè)置 additivity=false。
?
4. 生產(chǎn)環(huán)境禁止直接使用 System.out 或 System.err 輸出日志或使用e.printStackTrace()打印異常堆棧。
?
5. 異常信息應(yīng)該包括兩類信息:案發(fā)現(xiàn)場信息和異常堆棧信息。
?
6. 日志打印時禁止直接用 JSON 工具將對象轉(zhuǎn)換成 String。
說明:如果對象里某些 get 方法被覆寫,存在拋出異常的情況,則可能會因為打印日志而影響正常業(yè)務(wù)流程的執(zhí)行。
正例:打印日志時僅打印出業(yè)務(wù)相關(guān)屬性值或者調(diào)用其對象的 toString()方法。?
說明:大量地輸出無效日志,不利于系統(tǒng)性能提升,也不利于快速定位錯誤點。
?
8. 可以使用 warn 日志級別來記錄用戶輸入?yún)?shù)錯誤的情況,避免用戶投訴時,無所適從。如非必要,請不要在此場景打出 error 級別,避免頻繁報警。
?
?
其他規(guī)范
?
打印日志中的"不要"
1. 不要使用System.out.println打印日志
初學者一般在開發(fā)中或者調(diào)試bug的時候,都會習慣性的使用System.out.println語句,輸出到控制臺中,觀察數(shù)據(jù)是否正常。開發(fā)或者調(diào)試完畢,很可能就忘記刪除,直接就發(fā)布到生產(chǎn)中去了。
而在生產(chǎn)環(huán)境中,禁止使用System.out.println有兩點原因:
- 當需要查看日志時,往往是從日志文件中去查看的。使用System.out.println,只會將日志打印到控制臺,并不會保存到日志文件中。
- System.out.println是一個同步方法,在高并發(fā)的情況下,會嚴重影響性能。
2. 不要使用e.printStackTrace()
反例:
正例:
try{// 業(yè)務(wù)代碼處理 }catch(Exception e){log.error("你的程序有異常啦",e); }理由:
- e.printStackTrace()打印出的堆棧日志跟業(yè)務(wù)代碼日志是交錯混合在一起的,通常排查異常日志不太方便。
- e.printStackTrace()語句產(chǎn)生的字符串記錄的是堆棧信息,如果信息太長太多,字符串常量池所在的內(nèi)存塊沒有空間了,即內(nèi)存滿了,那么,用戶的請求就卡住了
3.不要記錄了異常,又拋出異常
反例:
log.error("IO exception", e); throw new MyException(e);理由:
這樣實現(xiàn)的話,通常會把棧信息打印兩次。這是因為捕獲了MyException異常的地方,還會再打印一次。 這樣的日志記錄,或者包裝后再拋出去,不要同時使用!否則你的日志看起來會讓人很迷惑。
避免重復打印日志,只會浪費磁盤空間。如果你已經(jīng)有一行日志清楚表達了意思,避免再冗余打印。
反例
如果你是使用log4j日志框架,務(wù)必在log4j.xml中設(shè)置 additivity=false,因為可以避免重復打印日志.
<logger name="com.taobao.dubbo.config" additivity="false">打印日志的“要”
- 系統(tǒng)接受消息通道的消息開處理事務(wù)
- 系統(tǒng)開發(fā)接口供外部應(yīng)用調(diào)用等
理想的日志格式,應(yīng)當包括這些最基本的信息:如當前時間戳(一般毫秒精確度)、日志級別,線程名字等等。在logback日志里可以這么配置:
使用SLF4J框架,可以在部署時遷移到所需的日志記錄框架。這是因為SLF4J提供了對所有流行的日志框架的綁定,例如log4j,JUL,Simple logging和NOP。因此可以在部署時切換到任何這些流行的框架。
無論使用哪種綁定,SLF4J都支持參數(shù)化日志記錄消息。由于SLF4J將應(yīng)用程序和日志記錄框架分離, 因此可以輕松編寫?yīng)毩⒂谌罩居涗浛蚣艿膽?yīng)用程序。而無需擔心用于編寫應(yīng)用程序的日志記錄框架。
SLF4J提供了一個簡單的Java工具,稱為遷移器。使用此工具,可以遷移現(xiàn)有項目,這些項目使用日志 框架(如Jakarta Commons Logging(JCL)或log4j或Java.util.logging(JUL))到SLF4J。
建議使用參數(shù)占位{},而不是用+拼接。
這點上面講過了!
要打印出e, 輸出全部錯誤信息
反例1
說明:異常e都沒有打印出來,所以壓根不知道出了什么類型的異常。
反例2
try {//業(yè)務(wù)代碼處理 } catch (Exception e) {// 錯誤LOG.error('你的程序有異常啦', e.getMessage()); }說明:e.getMessage()不會記錄詳細的堆棧異常信息,只會記錄錯誤基本描述信息,不利于排查問題。
正例
try {//業(yè)務(wù)代碼處理 } catch (Exception e) {// 錯誤LOG.error('你的程序有異常啦', e); }總結(jié)
- 上一篇: html语言的核心是,WEB前端三大核心
- 下一篇: 易语言 mysql支持库支持多线程_易语