眾所周知,日志是排查問題的重要手段。關(guān)于日志設(shè)計(jì),以及怎么根據(jù)從【用戶報障】環(huán)節(jié)開始到秒級定位問題這個我們下一期說(絕非套路),這一期,主要講一下,在沒有異常日志的情況下
,如何定位問題。沒有日志當(dāng)真能排查問題,不會是標(biāo)題黨吧!
案例一
從最大的同性交友網(wǎng)站中拉取【dubbo-spring-boot-project】的代碼。
然后把demo跑起來。
本場景是由真實(shí)案例改編,因?yàn)楣敬a比較復(fù)雜也不方便透露,而這個demo在github上大家都能找到,既保證了原汁原味,又能讓大家方便自己體驗(yàn)排查過程。
好了,我們先設(shè)置owner = "feichao"
,然后看一下控制臺
一切正常
那么,當(dāng)我設(shè)置成owner = "feichaozhenshuai!"
,再啟動
看似一切都正常,那么,我們到控制臺一看。
什么情況,怎么就沒owner
了?
這是在哪個環(huán)節(jié)出問題了?其實(shí)肥朝當(dāng)初在公司遇到這個問題的時候,場景比這個復(fù)雜得多。因?yàn)楣镜臉I(yè)務(wù)里沒有owner的話,在運(yùn)行時會出現(xiàn)一些其他異常,涉及公司業(yè)務(wù)這里就不展開了,我們言歸正傳,為毛我設(shè)置成feichaozhenshuai!
就不行了,那我設(shè)置成肥朝大帥比
電腦會不會爆炸啊???
常見的錯誤做法
是,把這個問題截圖往群里一丟,問“你們有沒有遇到過dubbo里面,owner設(shè)置不生效的問題?”
而關(guān)注了肥朝公眾號的【真愛粉絲】會這么問,“dubbo里面設(shè)置owner卻不生效,你們覺得我要從個角度排查問題?”。一看到這么正確的提問方式,我覺得我不回復(fù)你都不好意思。好了,回到主題,這個時候,沒有一點(diǎn)點(diǎn)錯誤日志,但是卻設(shè)置不成功,我們有哪些排查手段?
套路一
直接找set方法,看看是不是代碼做了判斷,防止在owner
字段里面set類似肥朝真帥
這種詞語,避免把帥這件事走漏風(fēng)聲!
。這么一分析似乎挺有道理對吧,那么,如何快速找到這個set方法呢?如圖
public?void?setOwner(String?owner)?{
????checkMultiName("owner",?owner);
????this.owner?=?owner;
}
我們跟進(jìn)checkMultiName
代碼后發(fā)現(xiàn)
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
里面是只支持-
和_
等這類特殊符號,!
是不支持的,所以設(shè)置成不成功,和肥朝帥不帥是沒關(guān)系的,和后面的!
是有關(guān)系的。擦,原來是肥朝想多了,給自己加戲了!?。?/p>
當(dāng)然肥朝可以告訴你,在后面的版本,修復(fù)了這個bug,日志會看得到異常了。這個時候你覺得問題就解決了?
我相信此時很多假粉就會關(guān)掉文章,或者說下次肥朝發(fā)了一些他們不喜歡看的文章(你懂的)后,他們就從此取關(guān),但是肥朝想說,且慢動手!??!
你想嘛,萬一你以后又遇到類似的問題呢?而且源碼層次很深,就不是簡單的搜個set
方法這么簡單,這次給你搜到了set方法并解決問題,簡直是偶然成功
。因此,我才多次強(qiáng)調(diào),要持續(xù)關(guān)注肥朝,掌握更多套路。這難道是想騙你關(guān)注?我這分明是愛你??!
那么,萬一以后遇到一些吞掉異常
,亦或者某些原因?qū)е?code style="margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;background: rgb(248, 245, 236);color: rgb(255, 53, 2);line-height: 1.5;font-size: 90%;padding: 3px 5px;border-radius: 2px;">日志沒打印,我們到底如何排查?
套路二
我們知道idea里面有很多好用的功能,比如肥朝之前的【看源碼,我為什么推薦IDEA?】中就提到了條件斷點(diǎn)
,除此之外,還有一個被大家低估的功能,叫做異常斷點(diǎn)
。
肥朝掃了一眼,里面的單詞都是小學(xué)的英語單詞,因此怎么使用就不做過多解釋。遇到這個問題時,我們可以這樣設(shè)置異常斷點(diǎn)。
運(yùn)行起來如下:
這樣,運(yùn)行起來的時候,就會迅速定位到異常位置。然后一頓分析,應(yīng)該很容易找出問題。
是不是有點(diǎn)感覺了?那我們再來一個題型練習(xí)一下。
案例二
我們先在看之前肥朝粉絲群的提問
考慮到部分粉絲不在群里,我就簡單描述一下這個粉絲的問題,他代碼有個異常,然后catch打異常日志,但是日志卻沒輸出。
當(dāng)然你還是不理解也沒關(guān)系,我根據(jù)該粉絲的問題,給你搭建了一個最簡模型的demo,模型雖然簡單,但是問題是同樣的,原汁原味,熟悉的配方,熟悉的味道。git地址如下:【https://gitee.com/HelloToby/springboot-run-exception】我們運(yùn)行起來看一下
@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("歡迎關(guān)注微信公眾號【肥朝】");
????}
????@Override
????public?void?contextLoaded(ConfigurableApplicationContext?context)?{
????}
????@Override
????public?void?finished(ConfigurableApplicationContext?context,?Throwable?exception)?{
????}
}
你會發(fā)現(xiàn),一運(yùn)行起來進(jìn)程就停止,一點(diǎn)日志都沒。絕大部分假粉絲遇到這個情況,都是菊花一緊,一點(diǎn)頭緒都沒,又去群里問”你們有沒有遇到過,Springboot一起來進(jìn)程就沒了,但是沒有日志的問題?“。正確提問姿勢肥朝已經(jīng)強(qiáng)調(diào)過,這里不多說。那么我們用前面學(xué)到的排查套路,再來走一波
我們根據(jù)異常棧順藤摸瓜
我們從代碼中看出兩個關(guān)鍵單詞【reportFailure】、【context.close()】,經(jīng)過斷點(diǎn)我們發(fā)現(xiàn),確實(shí)是會先打印日志,再關(guān)掉容器。但是為啥日志先執(zhí)行,再關(guān)掉容器,日志沒輸出,容器就關(guān)掉了呢?因?yàn)?,這個demo中,日志是全異步日志,異步日志還沒執(zhí)行,容器就關(guān)了,導(dǎo)致了日志沒有輸出。
該粉絲遇到的問題是類似的,他是單元測試中,代碼中的異步日志還沒輸出,單元測試執(zhí)行完進(jìn)程就停止了。知道了原理解決起來也很簡單,比如最簡單的,跑單元測試的時候末尾先sleep一下等日志輸出。
在使用Springboot中,其實(shí)經(jīng)常會遇到這種,啟動期間出現(xiàn)異常,但是日志是異步的,日志還沒輸出就容器停止,導(dǎo)致沒有異常日志。知道了原理之后,要徹底解決這類問題,可以增加一個SpringApplicationRunListener
。
/**
?*?負(fù)責(zé)應(yīng)用啟動時的異常輸出
?*/
@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);
????????????}
????????}
????}
}
再啰嗦一句,其實(shí)日志輸出不了,除了這個異步日志的案例外,還有很多情況的,比如日志沖突之類的,排查套路還很多,因此,建議持續(xù)關(guān)注,每一個套路,都想和你分享!
什么是編程思想?
肥朝始終覺得,要想比別人更優(yōu)秀,除了比別人更努力這個必要因素外,思維方式,也是我們必要關(guān)注的一個重點(diǎn)。比如在案例二中,很多同學(xué)知道了bug之后,就認(rèn)為自己學(xué)到東西了,其實(shí)這個想法既正確,也不正確。
正確的地方在于,你知道了這個bug,后面遇到相同的問題,你會猜一下是不是同樣的原因。
不正確的地方在于,你只知道了這個bug出現(xiàn)的某個場景,但是當(dāng)我們遇到這個問題,應(yīng)對的排查套路有哪些你并不知道。也就是說,如果這個問題過后,你排查問題的套路并沒有增加,亦或者你沒有能從這個問題上,發(fā)散出自己的想法,繼續(xù)壓榨出更多的價值,本質(zhì)上,你的編程能力,其實(shí)并沒有提升的。
然而,你一旦在公司時間長了,也就是我們常說的老油條,對公司的某些坑熟悉,新人遇到問題時,就容易猜對可能是某個坑。但是其實(shí)你的套路來來去去就那幾個,本質(zhì)上你的編程能力并沒有提升,卻讓你產(chǎn)生了自己越來越牛逼,這下必須要加薪的錯覺。
一個公司總是有線上報障是有問題的,但是一直不出問題也有問題的。當(dāng)然很多時候,排查的機(jī)會或許輪不到你。這個時候,就會有常見的幾種做法。
1.公司確實(shí)項(xiàng)目太簡單,基本沒有什么拿得出手的bug,都是一些低級的漏掉配置的bug。
2.大佬們在排查,反正不是我的問題,那我就看群吹吹水,下班美滋滋。
3.大佬們在排查,等他們有結(jié)論了,我就過去問一句是啥問題,然后暗自記下來,下次面試的時候就說是自己排查的,吹一波,美滋滋。
4.大佬們在排查,得知原因后,深入思考,大佬們?yōu)樯稌氲绞沁@個原因,他們是怎么排查的?用了哪些排查工具?排查技巧?然后暗自總結(jié)一波,并把自己代入場景,腦補(bǔ)一下自己來排查問題,并把這個bug壓榨出更多價值?。ㄔ趺磯赫コ龈鄡r值,可以查看肥朝之前的源碼實(shí)戰(zhàn)文章,每一篇都有一個環(huán)節(jié)專門講拓展思考的)
你的思維方式,你的行動,往往就決定你成為什么樣的人。
特別推薦一個分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長按關(guān)注一下:
長按訂閱更多精彩▼
如有收獲,點(diǎn)個在看,誠摯感謝
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!