小白入門學習打日誌
- 2019 年 10 月 7 日
- 筆記

來源:Java3y
作者:Java3y
一、Java打日誌的基礎
以前自己自學的時候,排查問題只會寫下面的代碼:
try { // doSomething } catch (Exception e) { e.printStackTrace(); } ---------- // 查看某個數據的值時: System.out.println(xxxx);
去到公司就發現上面的代碼全不見了,剩下的是:
LOGGER.info("begin to run Java3y:{}", id); ---- LOGGER.error("excepiton occurs when run Java3y {}, exception{}", id, e.toString());
如果使用e.printStackTrace();
的話,打印在控制的信息分析不方便:

打印在控制的信息分析不方便
而我們將信息分等級和時間記錄在服務器的磁盤上,有問題了就可以根據對應的信息去查找相關的日誌(這樣排查起來是十分方便的):

服務器上的日誌信息
我們再來看一下一般的日誌長什麼樣的:

日誌長的是什麼樣的
例如:現在有人來反饋某某某用戶好像收不到短訊,給出發送時間和用戶ID,我們就可以在日誌上找出該用戶在我們系統的發送狀態(例如圖上的:state:81,我們就認為是發送成功狀態)
那麼,問題來了,我們在哪打日誌?《手冊》上其實已經給出了答案:
謹慎地記錄日誌。生產環境禁止輸出 debug 日誌;有選擇地輸出 info 日誌;如果使 用 warn 來記錄剛上線時的業務行為信息,一定要注意日誌輸出量的問題,避免把服務器磁盤 撐爆,並記得及時刪除這些觀察日誌。 大量地輸出無效日誌,不利於系統性能提升,也不利於快速定位錯誤點。記錄日誌時請思考:這些 日誌真的有人看嗎?看到這條日誌你能做什麼?能不能給問題排查帶來好處?
1.1什麼叫做 打點 ?
打日誌最常見的就是用來打印出程序執行時的相關信息,用於快速定位問題和排查問題。我一開始也是這麼理解的,但是其實還可以延伸一下。
我現在搞的那個系統,我們還使用日誌在系統的執行鏈路上打點。比如說,我現在要推送一條通知消息,通知消息其實就是下面這種:

這就是通知消息
這個過程大概是如此的:
- 首先別人調用我的RPC提供的接口(或者我自己調用自己的接口),發現這是一個通知消息。於是我組裝成對應的Task,異步放到消息隊列中
- 另一個系統從消息隊列中取出Task,對這個Task進行業務的處理(比如說是否夜間屏蔽,是否強制發送等等),然後調用HTTP接口把這個Task交給下游
- 下游做的事其實也很多,整塊鏈路很長(比如要調用SDK的庫,Android和IOS又做不同的處理)

整塊鏈路
而我們又希望在推送完了之後能統計出一些指標(曝光量,點擊率,轉化率)等等。於是乎,就需要在一些關鍵的位置上打一個日誌(專業點叫做打點)
在整塊鏈路都打通了以後,將這些點位(日誌)收集起來,放到實時流式處理平台(storm/flink)上清洗/過濾。如果是實時需要用到的放到Redis,離線的放在Hive。
二、手冊規範
2.1 使用門面模式的日誌框架
【強制】應用中不可直接使用日誌系統(Log4j、Logback)中的 API,而應依賴使用日誌框架 SLF4J 中的 API,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。
門面模式我之前也寫過一篇筆記:三分鐘學會門面模式!
其實說白了就是希望抽象出一層API,能夠在切換具體日誌框架的時候不需要大面積更改。
這個我們可以按學JDBC的時候去理解:
無論我是接入MySQL、Oracle還是SQL Server,但我的接口永遠都是那一套,切換數據庫時不需要更改我的Java API
看了一下公司的項目,採用的是SLF4J+Logback
2.2 調用RPC接口使用Throwable類攔截
【強制】在調用 RPC、二方包、或動態生成類的相關方法時,捕捉異常必須使用 Throwable 類來進行攔截。
之前在排查問題的時候,有個問題死活排不出來,DeBug的時候一直沒進catch模塊。後來我學長就說:「要不你改成Throwable試試?
try { } catch (Throwable e) { }
我就很疑問,說:「為啥要改成Throwable呢?我們用Exception不就可以捕獲所有的異常了么,Exception是Throwable的一個子類,但Exception已經是包含所有的Java異常了呀」
眾所周知,Throwable有兩個子類:
- Error(一般我們都會把這個忽略掉…一般情況下出現了Error程序都運行不起來)
- Exception
The Throwable class is the superclass of all errors and exceptions in the Java language
在《手冊》上也有對上面的規則進行說明:
說明:通過反射機制來調用方法,如果找不到方法,拋出 NoSuchMethodException。什麼情況會拋出 NoSuchMethodError 呢?二方包在類衝突時,仲裁機制可能導致引入非預期的版本使類的方法簽名不匹 配,或者在位元組碼修改框架(比如:ASM)動態創建或修改類時,修改了相應的方法簽名。這些情況,即 使代碼編譯期是正確的,但在代碼運行期時,會拋出 NoSuchMethodError。
大概的意思就是說:調用 RPC、二方包、或動態生成類的相關方法時,可能直接拋出的是Error,而catch Exception是無法捕獲得到的。
想看例子的同學可以看看這篇文章:
- https://zhuanlan.zhihu.com/p/57950399