衆所周知,日誌是排查問題的重要手段。關於日誌設計,以及怎麼根據從【用戶報障】環節開始到秒級定位問題這個咱們下一期說(絕非套路),這一期,主要講一下,在沒有異常日誌的狀況下
,如何定位問題。沒有日誌當真能排查問題,不會是標題黨吧!git
從最大的同性交友網站中拉取【dubbo-spring-boot-project】的代碼。github
而後把demo跑起來。面試
本場景是由真實案例改編,由於公司代碼比較複雜也不方便透露,而這個demo在github上你們都能找到,既保證了原汁原味,又能讓你們方便本身體驗排查過程。spring
好了,咱們先設置owner = "feichao"
,而後看一下控制檯編程
一切正常springboot
那麼,當我設置成owner = "feichaozhenshuai!"
,再啓動微信
看似一切都正常,那麼,咱們到控制檯一看。app
什麼狀況,怎麼就沒owner
了?異步
這是在哪一個環節出問題了?其實肥朝當初在公司遇到這個問題的時候,場景比這個複雜得多。由於公司的業務裏沒有owner的話,在運行時會出現一些其餘異常,涉及公司業務這裏就不展開了,咱們言歸正傳,爲毛我設置成feichaozhenshuai!
就不行了,那我設置成肥朝大帥比
電腦會不會爆炸啊???ide
常見的錯誤作法
是,把這個問題截圖往羣裏一丟,問「大家有沒有遇到過dubbo裏面,owner設置不生效的問題?」
而關注了肥朝公衆號的【真愛粉絲】會這麼問,「dubbo裏面設置owner卻不生效,大家以爲我要從個角度排查問題?」。一看到這麼正確的提問方式,我以爲我不回覆你都很差意思。好了,回到主題,這個時候,沒有一點點錯誤日誌,可是卻設置不成功,咱們有哪些排查手段?
直接找set方法,看看是否是代碼作了判斷,防止在owner
字段裏面set相似肥朝真帥
這種詞語,避免把帥這件事走露風聲!
。這麼一分析彷佛挺有道理對吧,那麼,如何快速找到這個set方法呢?如圖
public void setOwner(String owner) {
checkMultiName("owner", owner);
this.owner = owner;
}
咱們跟進checkMultiName
代碼後發現
protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
if (StringUtils.isEmpty(value)) {
return;
}
if (value.length() > maxlength) {
throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength);
}
if (pattern != null) {
Matcher matcher = pattern.matcher(value);
if (!matcher.matches()) {
throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " +
"character, only digit, letter, '-', '_' or '.' is legal.");
}
}
}
從異常描述就很明顯能夠看出,原來owner
裏面是隻支持-
和_
等這類特殊符號,!
是不支持的,因此設置成不成功,和肥朝帥不帥是不要緊的,和後面的!
是有關係的。擦,原來是肥朝想多了,給本身加戲了!!!
固然肥朝能夠告訴你,在後面的版本,修復了這個bug,日誌會看獲得異常了。這個時候你以爲問題就解決了?
我相信此時不少假粉就會關掉文章,或者說下次肥朝發了一些他們不喜歡看的文章(你懂的)後,他們就今後取關,可是肥朝想說,且慢動手!!!
你想嘛,萬一你之後又遇到相似的問題呢?並且源碼層次很深,就不是簡單的搜個set
方法這麼簡單,此次給你搜到了set方法並解決問題,簡直是偶然成功
。所以,我才屢次強調,要持續關注肥朝,掌握更多套路。這難道是想騙你關注?我這分明是愛你啊!
那麼,萬一之後遇到一些吞掉異常
,亦或者某些緣由致使日誌沒打印
,咱們到底如何排查?
咱們知道idea裏面有不少好用的功能,好比肥朝以前的【看源碼,我爲何推薦IDEA?】中就提到了條件斷點
,除此以外,還有一個被你們低估的功能,叫作異常斷點
。
肥朝掃了一眼,裏面的單詞都是小學的英語單詞,所以怎麼使用就不作過多解釋。遇到這個問題時,咱們能夠這樣設置異常斷點。
運行起來以下:
這樣,運行起來的時候,就會迅速定位到異常位置。而後一頓分析,應該很容易找出問題。
是否是有點感受了?那咱們再來一個題型練習一下。
咱們先在看以前肥朝粉絲羣的提問
考慮到部分粉絲不在羣裏,我就簡單描述一下這個粉絲的問題,他代碼有個異常,而後catch打異常日誌,可是日誌卻沒輸出。
固然你仍是不理解也不要緊,我根據該粉絲的問題,給你搭建了一個最簡模型的demo,模型雖然簡單,可是問題是一樣的,原汁原味,熟悉的配方,熟悉的味道。git地址以下:【https://gitee.com/HelloToby/springboot-run-exception】咱們運行起來看一下
@Slf4j
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
public HelloSpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
throw new RuntimeException("歡迎關注微信公衆號【肥朝】");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
}
}
你會發現,一運行起來進程就中止,一點日誌都沒。絕大部分假粉絲遇到這個狀況,都是菊花一緊,一點頭緒都沒,又去羣裏問」大家有沒有遇到過,Springboot一塊兒來進程就沒了,可是沒有日誌的問題?「。正確提問姿式肥朝已經強調過,這裏很少說。那麼咱們用前面學到的排查套路,再來走一波
咱們根據異常棧順藤摸瓜
咱們從代碼中看出兩個關鍵單詞【reportFailure】、【context.close()】,通過斷點咱們發現,確實是會先打印日誌,再關掉容器。可是爲啥日誌先執行,再關掉容器,日誌沒輸出,容器就關掉了呢?由於,這個demo中,日誌是全異步日誌,異步日誌還沒執行,容器就關了,致使了日誌沒有輸出。
該粉絲遇到的問題是相似的,他是單元測試中,代碼中的異步日誌還沒輸出,單元測試執行完進程就中止了。知道了原理解決起來也很簡單,好比最簡單的,跑單元測試的時候末尾先sleep一下等日誌輸出。
在使用Springboot中,其實常常會遇到這種,啓動期間出現異常,可是日誌是異步的,日誌還沒輸出就容器中止,致使沒有異常日誌。知道了原理以後,要完全解決這類問題,能夠增長一個SpringApplicationRunListener
。
/**
* 負責應用啓動時的異常輸出
*/
@Slf4j
public class OutstandingExceptionReporter implements SpringApplicationRunListener {
public OutstandingExceptionReporter(SpringApplication application, String[] args) {
}
@Override
public void starting() {
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
if (exception != null) {
log.error("application started failed",exception);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.error("application started failed", e);
}
}
}
}
再囉嗦一句,其實日誌輸出不了,除了這個異步日誌的案例外,還有不少狀況的,好比日誌衝突之類的,排查套路還不少,所以,建議持續關注,每個套路,都想和你分享!
肥朝始終以爲,要想比別人更優秀,除了比別人更努力這個必要因素外,思惟方式,也是咱們必要關注的一個重點。好比在案例二中,不少同窗知道了bug以後,就認爲本身學到東西了,其實這個想法既正確,也不正確。
正確的地方在於,你知道了這個bug,後面遇到相同的問題,你會猜一下是否是一樣的緣由。
不正確的地方在於,你只知道了這個bug出現的某個場景,可是當咱們遇到這個問題,應對的排查套路有哪些你並不知道。也就是說,若是這個問題事後,你排查問題的套路並無增長,亦或者你沒有能從這個問題上,發散出本身的想法,繼續壓榨出更多的價值,本質上,你的編程能力,其實並無提高的。
然而,你一旦在公司時間長了,也就是咱們常說的老油條,對公司的某些坑熟悉,新人遇到問題時,就容易猜對多是某個坑。可是其實你的套路來來去去就那幾個,本質上你的編程能力並無提高,卻讓你產生了本身愈來愈牛逼,這下必需要加薪的錯覺。
一個公司老是有線上報障是有問題的,可是一直不出問題也有問題的。固然不少時候,排查的機會或許輪不到你。這個時候,就會有常見的幾種作法。
1.公司確實項目太簡單,基本沒有什麼拿得出手的bug,都是一些低級的漏掉配置的bug。
2.大佬們在排查,反正不是個人問題,那我就看羣吹吹水,下班美滋滋。
3.大佬們在排查,等他們有結論了,我就過去問一句是啥問題,而後暗自記下來,下次面試的時候就說是本身排查的,吹一波,美滋滋。
4.大佬們在排查,得知緣由後,深刻思考,大佬們爲啥會想到是這個緣由,他們是怎麼排查的?用了哪些排查工具?排查技巧?而後暗自總結一波,並把本身代入場景,腦補一下本身來排查問題,並把這個bug壓榨出更多價值!(怎麼壓榨出更多價值,能夠查看肥朝以前的源碼實戰文章,每一篇都有一個環節專門講拓展思考的)
你的思惟方式,你的行動,每每就決定你成爲何樣的人。肥朝也始終相信,時間在哪,行動在哪,成就就在哪。一塊兒共勉。