前言
只有光頭才能變強(qiáng)。
文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3y
<https://github.com/ZhongFuCheng3y/3y>
記得之前寫過一篇:《阿里巴巴 Java開發(fā)手冊》讀后感
<https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484402&idx=1&sn=786686c4d2abd958c535065de044701d&chksm=ebd742f3dca0cbe5f6f401e38391369f28287858125d52a1a169523dc4f9600e20335446a629&token=620000779&lang=zh_CN&scene=21#wechat_redirect>
,之前自學(xué)時(shí)由于沒怎么接觸過打“日志”,所以《手冊》中的“日志規(guī)約”我就先放一邊去了。
而之前寫了一篇:在公司做的項(xiàng)目和自己在學(xué)校做的有什么區(qū)別?
<https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247485368&idx=1&sn=59742409160a103eddaa6ca187a77256&chksm=ebd746b9dca0cfaffd61b35a810d806f7eea67c5a0dec820ae65be093d81abf49ac19ab1248b&token=2078489135&lang=zh_CN#rd>
中就有提到:公司的項(xiàng)目不會有e.printStackTrace();這種代碼的存在。因?yàn)檫@打印出來的錯(cuò)誤信息沒有日期、等級等等,分析起來不方便。
在工作中去服務(wù)器上查日志又是一個(gè)非常非常常見的操作,所以當(dāng)初我又寫了一篇 工作中常用到的Linux命令
<https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247485440&idx=1&sn=85b40c173d66b62b3e870dd0e095c72c&chksm=ebd74901dca0c01727ed2cff30acc5d39948eda5bf4252f1d96526f951591f69edcfccbbad29&token=2078489135&lang=zh_CN#rd>
,里邊就談到了查日志時(shí)常用的Linux命令。
想著,既然接觸日志也有一段時(shí)間了,不妨在回看《手冊》,看看有什么要注意的地方,于是就有了這篇筆記。
一、Java打日志的基礎(chǔ)
以前自己自學(xué)的時(shí)候,排查問題只會寫下面的代碼:
try { // doSomething } catch (Exception e) { e.printStackTrace(); } ----------
// 查看某個(gè)數(shù)據(jù)的值時(shí): System.out.println(xxxx);
去到公司就發(fā)現(xiàn)上面的代碼全不見了,剩下的是:
LOGGER.info("begin to run Java3y:{}", id); ---- LOGGER.error("excepiton occurs
when run Java3y {}, exception{}", id, e.toString());
如果使用e.printStackTrace();的話,打印在控制的信息分析不方便:
而我們將信息分等級和時(shí)間記錄在服務(wù)器的磁盤上,有問題了就可以根據(jù)對應(yīng)的信息去查找相關(guān)的日志(這樣排查起來是十分方便的):
我們再來看一下一般的日志長什么樣的:
例如:現(xiàn)在有人來反饋某某某用戶好像收不到短信,給出發(fā)送時(shí)間和用戶ID
,我們就可以在日志上找出該用戶在我們系統(tǒng)的發(fā)送狀態(tài)(例如圖上的:state:81,我們就認(rèn)為是發(fā)送成功狀態(tài))
那么,問題來了,我們在哪打日志?《手冊》上其實(shí)已經(jīng)給出了答案:
謹(jǐn)慎地記錄日志。生產(chǎn)環(huán)境禁止輸出 debug 日志;有選擇地輸出 info 日志;如果使
用 warn 來記錄剛上線時(shí)的業(yè)務(wù)行為信息,一定要注意日志輸出量的問題,避免把服務(wù)器磁盤
撐爆,并記得及時(shí)刪除這些觀察日志。
大量地輸出無效日志,不利于系統(tǒng)性能提升,也不利于快速定位錯(cuò)誤點(diǎn)。記錄日志時(shí)請思考:這些
日志真的有人看嗎?看到這條日志你能做什么?能不能給問題排查帶來好處?
1.1什么叫做 打點(diǎn) ?
打日志最常見的就是用來打印出程序執(zhí)行時(shí)的相關(guān)信息,用于快速定位問題和排查問題。我一開始也是這么理解的,但是其實(shí)還可以延伸一下。
我現(xiàn)在搞的那個(gè)系統(tǒng),我們還使用日志在系統(tǒng)的執(zhí)行鏈路上打點(diǎn)。比如說,我現(xiàn)在要推送一條通知消息,通知消息其實(shí)就是下面這種:
這個(gè)過程大概是如此的:
* 首先別人調(diào)用我的RPC提供的接口(或者我自己調(diào)用自己的接口),發(fā)現(xiàn)這是一個(gè)通知消息。于是我組裝成對應(yīng)的Task,異步放到消息隊(duì)列中
* 另一個(gè)系統(tǒng)從消息隊(duì)列中取出Task,對這個(gè)Task進(jìn)行業(yè)務(wù)的處理(比如說是否夜間屏蔽,是否強(qiáng)制發(fā)送等等),然后調(diào)用HTTP接口把這個(gè)Task交給下游
* 下游做的事其實(shí)也很多,整塊鏈路很長(比如要調(diào)用SDK的庫,Android和IOS又做不同的處理)
而我們又希望在推送完了之后能統(tǒng)計(jì)出一些指標(biāo)(曝光量,點(diǎn)擊率,轉(zhuǎn)化率)等等。于是乎,就需要在一些關(guān)鍵的位置上打一個(gè)日志(專業(yè)點(diǎn)叫做打點(diǎn))
在整塊鏈路都打通了以后,將這些點(diǎn)位
(日志)收集起來,放到實(shí)時(shí)流式處理平臺(storm/flink)上清洗/過濾。如果是實(shí)時(shí)需要用到的放到Redis,離線的放在Hive。
二、手冊規(guī)范
2.1 使用門面模式的日志框架
【強(qiáng)制】應(yīng)用中不可直接使用日志系統(tǒng)(Log4j、Logback)中的 API,而應(yīng)依賴使用日志框架
SLF4J 中的 API,使用門面模式的日志框架,有利于維護(hù)和各個(gè)類的日志處理方式統(tǒng)一。
門面模式我之前也寫過一篇筆記:三分鐘學(xué)會門面模式!
<https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484556&idx=1&sn=920d00416ef76669b59937c771526345&chksm=ebd7458ddca0cc9bdda893fa034da354d97cfd0e96bdaa6ccfc2a94a0ba85a564415efa3c6ba&token=1712662964&lang=zh_CN#rd>
其實(shí)說白了就是希望抽象出一層API,能夠在切換具體日志框架的時(shí)候不需要大面積更改。
這個(gè)我們可以按學(xué)JDBC的時(shí)候去理解:
無論我是接入MySQL、Oracle還是SQL Server,但我的接口永遠(yuǎn)都是那一套,切換數(shù)據(jù)庫時(shí)不需要更改我的Java API
看了一下公司的項(xiàng)目,采用的是SLF4J+Logback
2.2 調(diào)用RPC接口使用Throwable類攔截
【強(qiáng)制】在調(diào)用 RPC、二方包、或動態(tài)生成類的相關(guān)方法時(shí),捕捉異常必須使用 Throwable
類來進(jìn)行攔截。
之前在排查問題的時(shí)候,有個(gè)問題死活排不出來,DeBug的時(shí)候一直沒進(jìn)catch模塊。后來我學(xué)長就說:“要不你改成Throwable試試?
try { } catch (Throwable e) { }
我就很疑問,說:“為啥要改成Throwable呢?我們用Exception不就可以捕獲所有的異常了么,Exception是Throwable的一個(gè)子類,但Exception已經(jīng)是包含所有的Java異常了呀”
眾所周知,Throwable有兩個(gè)子類:
* Error(一般我們都會把這個(gè)忽略掉...一般情況下出現(xiàn)了Error程序都運(yùn)行不起來)
* Exception The Throwable class is the superclass of all errors and
exceptions in the Java language
在《手冊》上也有對上面的規(guī)則進(jìn)行說明:
說明:通過反射機(jī)制來調(diào)用方法,如果找不到方法,拋出 NoSuchMethodException。什么情況會拋出
NoSuchMethodError 呢?二方包在類沖突時(shí),仲裁機(jī)制可能導(dǎo)致引入非預(yù)期的版本使類的方法簽名不匹
配,或者在字節(jié)碼修改框架(比如:ASM)動態(tài)創(chuàng)建或修改類時(shí),修改了相應(yīng)的方法簽名。這些情況,即
使代碼編譯期是正確的,但在代碼運(yùn)行期時(shí),會拋出 NoSuchMethodError。
大概的意思就是說:調(diào)用 RPC、二方包、或動態(tài)生成類的相關(guān)方法時(shí),可能直接拋出的是Error,而catch Exception是無法捕獲得到的。
想看例子的同學(xué)可以看看這篇文章:
* https://zhuanlan.zhihu.com/p/57950399
<https://zhuanlan.zhihu.com/p/57950399>
最后
參考資料(阿里巴巴開發(fā)手冊下載地址):
* https://github.com/alibaba/p3c <https://github.com/alibaba/p3c>
查閱資料時(shí)發(fā)現(xiàn)的好文:
*
https://www.cnblogs.com/chenhongliang/p/5312517.html
<https://www.cnblogs.com/chenhongliang/p/5312517.html>
*
https://www.cnblogs.com/crazyacking/p/5456347.html
<https://www.cnblogs.com/crazyacking/p/5456347.html>
樂于輸出干貨的Java技術(shù)公眾號:Java3y。公眾號內(nèi)有200多篇原創(chuàng)技術(shù)文章、海量視頻資源、精美腦圖,關(guān)注即可獲?。?br>
覺得我的文章寫得不錯(cuò),點(diǎn)贊!
熱門工具 換一換