無異常日誌,就不能排查問題了???

小聲逼逼

衆所周知,日誌是排查問題的重要手段。關於日誌設計,以及怎麼根據從【用戶報障】環節開始到秒級定位問題這個我們下一期說(絕非套路),這一期,主要講一下,在沒有異常日誌的情況下,如何定位問題。沒有日誌當真能排查問題,不會是標題黨吧!

圖片

案例一

從最大的同性交友網站中拉取【dubbo-spring-boot-project】的代碼。

圖片

然後把demo跑起來。

本場景是由真實案例改編,因爲公司代碼比較複雜也不方便透露,而這個demo在github上大家都能找到,既保證了原汁原味,又能讓大家方便自己體驗排查過程。

好了,我們先設置owner = "feichao",然後看一下控制檯



一切正常

那麼,當我設置成owner = "feichaozhenshuai!",再啓動


看似一切都正常,那麼,我們到控制檯一看。


什麼情況,怎麼就沒owner了?

這是在哪個環節出問題了?其實肥朝當初在公司遇到這個問題的時候,場景比這個複雜得多。因爲公司的業務裏沒有owner的話,在運行時會出現一些其他異常,涉及公司業務這裏就不展開了,我們言歸正傳,爲毛我設置成feichaozhenshuai!就不行了,那我設置成肥朝大帥比電腦會不會爆炸啊???


常見的錯誤做法是,把這個問題截圖往羣裏一丟,問“你們有沒有遇到過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壓榨出更多價值!(怎麼壓榨出更多價值,可以查看肥朝之前的源碼實戰文章,每一篇都有一個環節專門講拓展思考的)

你的思維方式,你的行動,往往就決定你成爲什麼樣的人。肥朝也始終相信,時間在哪,行動在哪,成就就在哪。一起共勉。



圖片


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章