源自我在知乎上的一个回答

我说的可能不是debug,主要是生产环境出问题时的查错。

借助日志查线上问题

首先,开发的时候就做好准备。

包括但不限于:

  • 好好记录日志。 一定要记录方法的入参、出参、异常信息。

  • 准备好日志下载、分析的工具。 必要时候日志拆分、分析脚本要能写出来。

前两天上线时,不停的收到报错邮件。而且邮件里发送来的errmsg居然是null。

当时的debug的关键三步。

第一是日志下载。生产环境有比较完善的日志机制,我把报错前一个小时的都扒了下来。

第二是日志分析,对比日志流,发现第x行日志打印之后,第x+n行没有打印。于是很清楚的确定,问题就在这n行之内。

最后再查看第x行记录的入参数据——入参是个javabean,日志里把其中所有非null的数据都记录了下来。于是很清楚的看到“feeExp=无”。

从日志下载到找到“无”,前后不超过10分钟。

然后我让系统管理员修改了对应的配置数据,都没验证结果就陪媳妇看电影去了。

没然后了,那之后直到现在,只发了一封错误邮件。后面说。

关于日志的一点tips

生产环境查错,好的日志真的是关键。曾经翻一份10G+的日志,满篇是“xx方法开始执行”“xx方法执行完毕”,什么数据都没有,真的有提刀砍人的心。

用log4j记录异常日志的时候,一定要用logger.error("error message in string",exception)这个重载方法。这个方法会把exception的异常信息堆栈一股脑打印出来。虽然不太友好,但是猴哥们应该都知道它的便利性。

熟悉流程

在此基础上,如果对系统业务、代码流程熟悉,可以走很大一条捷径。感谢那些好好设计代码结构的人。这样,出问题的时候,有时即使没有日志或者不看日志,也可以很轻松的就把问题锁定在三、四行代码里面。

今天上午收到了另一封报错邮件。这次有errmsg了,是“Integer can not cast into Double”。

因为是我自己写的代码,我对流程非常熟悉,并且我清楚的知道只有一个地方可能产生Integer强转Double——虽然不好意思承认,但确实是开发和测试时考虑不周全导致的。于是再次找管理员确认了一个配置数据,让她把一个“5”改成了“5.00”。再然后,我去写别的代码了。

重现错误

如果上面的步骤没法查出并解决问题,那么,你得能够重现错误。

这时候一个UAT环境的重要性就凸显出来了。

在上家工作的时候,由于是接手别人做了一半的系统,很多时候没日志可查(查了也只会有提刀砍人的冲动)。因此,大多数时候用户报告bug时,我们第一步都是去UAT环境上设法重现。UAT上是开了log4j的debug日志的(生产上考虑硬盘空间和性能原因,最多开到info,有的甚至只有error),有用的信息总比生产上要多一些。

而且=。=偶尔出现UAT无法重现的问题,我们会以此为借口告诉用户改不了……

UAT、INT、最后是到自己开发环境上重现,然后修改。

运气好的话,在重现过程中你能看到出错时打印出来的异常堆栈信息。由于没有生产环境那么大的系统压力,这时候就可以细细地慢慢地美美地……咀嚼一下这些信息了。

分析异常堆栈

我以前一直觉得看异常堆栈很简单,以至于跟同事急过眼,得找机会跟人家道歉去=。=刚才尝试整理看堆栈所需的能力(科技树?),发现能轻松看懂堆栈信息的猴哥,绝对不是一个简单的机枪兵或者大G。

第一得看得懂英语,或者能借助各类词典看懂那段英语;其次要懂异常机制,得从那一堆的at……和cause by ……中找到需要自己去关注、或者说自己有能力去关注的点。

而且常常还得懂一些编译啊classloader啊jvm啊服务器啊相关的东西;好记性或者烂笔头是个优势,因为好多问题会重复出现。

此外如果能够拥有脚踏实地的想象力能获得额外加成,因为有些异常信息真的太匪夷所思了。

上上次上线时候,我就遇到了这么个匪夷所思的问题。需要上线的代码在INT环境上跑的非常顺溜,上线的时候报了个NoClassDefFoundError。嘛……英语很好懂,no found的那个类也很清楚的跟在error的后面,但是……INT上真的非常顺溜啊……

这时,如果对系统业务、代码流程熟悉,又可以走很大一条捷径。很多次跟同事一起查错,他们还没看完日志我就猜到问题所在了,基本就是因为我走了这条捷径。

小结

总的来说,我查bug,基本上是依赖程序在运行中留下的信息。

大多数是我自己设置的“打卡机”,程序运行到这里就得打一次卡。有些是系统提供的帮助。当然会牺牲一些空间和时间的性能。不过目前来看,大多数是值得的。何况这些数据还可以拿来做点性能分析,甚至大数据分析呢。

借助这些信息,加上自己对系统、代码的掌握,大多数bug都能很迅速地定位、并最终解决。

学计算机的第一天老师就教我,“软件=数据+流程”。我到现在才算有了点切身的体会。日志里记录的是动态的数据,代码记录的是静态的流程。二者到手,bug无忧。

debug工具

debug这个工具,我在追查生产环境的bug时很少使用。真的,大多数情况下,日志+代码就足够了。

我只有在开发期间,调试一些复杂的算法,或者调试大批量数据时会用。

复杂算法是因为我人脑性能低,对代码流程分析不过来。

大数据量则是没法对各种数据状态一一去分析。

幸运——或者不行——的是,我基本没遇到过多少需要debug的情况。认认真真debug的事儿,做的应该不超过十次。

想了想,多线程并发也许是个不好用日志+代码来分析的东西。不过……我写的多线程……还没查过错……

哈哈一股浓浓的优越感是不是……不过说真的,代码较少出生产bug+出了bug能很快排查并解决,作为一只猴子我真的挺有成就感的