解决bug的技巧

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

首先,开发的时候就做好准备。
包括但不限于:
好好记录日志。一定要记录方法的入参、出参、异常信息。
准备好日志下载、分析的工具。必要时候日志拆分、分析脚本要能写出来。

前两天上线时,不停的收到报错邮件。而且邮件里发送来的errmsg居然是null。
当时的debug的关键三步,第一是日志下载。生产环境有比较完善的日志机制,我把报错前一个小时的都扒了下来。第二是日志分析,对比日志流,发现第x行日志打印之后,第x+n行没有打印。于是很清楚的确定,问题就在这n行之内。最后再查看第x行记录的入参数据——入参是个javabean,日志里把其中所有非null的数据都记录了下来。于是很清楚的看到“feeExp=无”。
从日志下载到找到“无”,前后不超过10分钟。
然后我让系统管理员修改了对应的配置数据,都没验证结果就陪媳妇看电影去了。
没然后了,那之后直到现在,只发了一封错误邮件。后面说。

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

小tip,用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这个工具,我在追查生产环境的bug时很少使用。真的,大多数情况下,日志+代码就足够了。
我只有在开发期间,调试一些复杂的算法,或者调试大批量数据时会用。复杂算法是因为我人脑性能低,对代码流程分析不过来。大数据量则是没法对各种数据状态一一去分析。幸运——或者不行——的是,我基本没遇到过多少需要debug的情况。认认真真debug的事儿,做的应该不超过十次。

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


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



本文转自 斯然在天边 51CTO博客,原文链接:http://blog.51cto.com/winters1224/1589495,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
24天前
|
缓存 前端开发 JavaScript
年度代码翻车现场 |前端代码评审问题总结
代码评审于技术团队的工程师文化建设非常有意义,它是形成团队统一代码风格最有效的方式,作者把自己团队在一年的CR中常见的那些小问题做了一些梳理,希望能对大家起到一点小帮助。
219378 4
|
10月前
机房重构遇到的BUG
机房重构遇到的BUG
41 0
|
12月前
|
Python
一日一技:你的代码是如何被炫技毁掉的
一日一技:你的代码是如何被炫技毁掉的
77 0
|
缓存 JavaScript 小程序
接手前同事代码,特别烂,各种BUG,看麻了。。。
接手前同事代码,特别烂,各种BUG,看麻了。。。
|
存储 程序员 编译器
【C/调试实用技巧】—作为程序员应如何面对并尝试解决Bug?
【C/调试实用技巧】—作为程序员应如何面对并尝试解决Bug?
106 0
|
Java 中间件 程序员
最网最全bug定位套路,遇见bug再也不慌了
最网最全bug定位套路,遇见bug再也不慌了
241 0
|
设计模式 架构师 Java
为什么有些蛮厉害的人,后来都不咋样了
写这篇文章目的是之前在一篇文章中谈到,我实习那会有个老哥很牛皮,业务能力嘎嘎厉害,但是后面发展一般般,这引起我的思考,最近有个同事发了篇腾讯pcg的同学关于review 相关的文章,里面也谈到架构师的层次,也再次引起我关于架构师的相关思考,接下来我们展开聊聊吧~
126 0
|
存储 Java 程序员
BeanDifinition(加几行代码,可以产出让队友几天也找不出的Bug)
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
167 0
|
XML 数据格式
解决Bug:OnErrorNotImplementedException
解决Bug:OnErrorNotImplementedException
334 0
解决Bug:OnErrorNotImplementedException
|
JSON Java 测试技术
如何写出让人抓狂的代码?
如何写出让人抓狂的代码?
如何写出让人抓狂的代码?