众所周知,日志是排查问题的重要手段。关于日志设计,以及怎么根据从【用户报障】环节开始到秒级定位问题这个咱们下一期说(绝非套路),这一期,主要讲一下,在没有异常日志的状况下
,如何定位问题。没有日志当真能排查问题,不会是标题党吧!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压榨出更多价值!(怎么压榨出更多价值,能够查看肥朝以前的源码实战文章,每一篇都有一个环节专门讲拓展思考的)
你的思惟方式,你的行动,每每就决定你成为何样的人。肥朝也始终相信,时间在哪,行动在哪,成就就在哪。一块儿共勉。