小聲逼逼
衆所周知,日誌是排查問題的重要手段。關於日誌設計,以及怎麼根據從【用戶報障】環節開始到秒級定位問題這個咱們下一期說(絕非套路),這一期,主要講一下,在沒有異常日誌的狀況下
,如何定位問題。沒有日誌當真能排查問題,不會是標題黨吧!java
案例一
從最大的同性交友網站中拉取【dubbo-spring-boot-project】的代碼。git
而後把demo跑起來。github
本場景是由真實案例改編,由於公司代碼比較複雜也不方便透露,而這個demo在github上你們都能找到,既保證了原汁原味,又能讓你們方便本身體驗排查過程。spring
好了,咱們先設置owner = "feichao"
,而後看一下控制檯springboot
一切正常微信
那麼,當我設置成owner = "feichaozhenshuai!"
,再啓動app
看似一切都正常,那麼,咱們到控制檯一看。異步
什麼狀況,怎麼就沒owner
了?ide
這是在哪一個環節出問題了?其實肥朝當初在公司遇到這個問題的時候,場景比這個複雜得多。由於公司的業務裏沒有owner的話,在運行時會出現一些其餘異常,涉及公司業務這裏就不展開了,咱們言歸正傳,爲毛我設置成feichaozhenshuai!
就不行了,那我設置成肥朝大帥比
電腦會不會爆炸啊???spring-boot
常見的錯誤作法
是,把這個問題截圖往羣裏一丟,問「大家有沒有遇到過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); } } } }
再囉嗦一句,其實日誌輸出不了,除了這個異步日誌的案例外,還有不少狀況的,好比日誌衝突之類的,排查套路還不少,所以,建議持續關注,每個套路,都想和你分享!
另外準備了一份資料,連接: https://pan.baidu.com/s/1M5-1RDL5FgVtC3fOHGhuBg 提取碼: wcdq
內含RocketMQ4.x文檔(市面上找到的多爲過期的3.x版本)