你如何修复一个你无法复制的错误?

cde*_*zaq 63 debugging replicate

问题就是这一切.如果您有多个用户报告的错误,但没有记录日志中发生的错误,也不能重复该错误,无论您如何努力,您如何解决?甚至可以吗?

我相信你们当中很多人都会遇到这种情况.你在这种情况下做了什么,最终的结果是什么?


编辑:我对一个不可修复的错误做了什么感兴趣,而不是一个无法解决的错误.无法解决的错误使得您至少知道存在问题并且在大多数情况下具有搜索它的起点.如果是不可能的,你做什么?你甚至可以做任何事情吗?

Dav*_*vis 78

这些被称为Heisenbugs.

语言

不同的编程语言会有各自的错误.

C

添加调试语句可能会使问题无法复制,因为调试语句本身会移动指针(足以避免SEGFAULT).指针问题是跟踪和复制的噩梦,但有些调试器(如GDBDDD)可以提供帮助.

Java的

具有多个线程的应用程序可能仅显示具有非常特定的时间或事件序列的错误.不正确的并发实现可能会在难以复制的情况下导致死锁.

JavaScript的

一些Web浏览器因内存泄漏而臭名昭着.在一个浏览器中运行良好的JavaScript代码可能会在另一个浏览器中导致错误行为 使用经过数千名用户严格测试的第三方库可能有利于避免某些模糊的错误.

环境

根据应用程序(具有错误)运行的环境的复杂性,唯一的办法可能是简化环境.应用程序是否运行:

  • 在服务器上?
  • 在桌面上?
  • 在网络浏览器?

应用程序在什么环境中产生问题?

  • 发展?
  • 测试?
  • 生产?

退出无关应用程序,终止后台任务,停止所有计划事件(cron作业),消除插件并卸载浏览器加载项.

联网

因为网络对于这么多应用程序至关重要:

  • 确保稳定的网络连接,包括无线信号.
  • 网络故障后软件是否重新连接?
  • 是否正确关闭所有连接以释放文件描述符?
  • 人们使用机器的人不应该是谁?
  • 恶意设备是否与机器网络交互?
  • 附近是否有可能造成干扰的工厂或无线电塔?
  • 数据包大小和频率是否在标称范围内?
  • 所有网络设备都适合大量使用带宽吗?

一致性

消除尽可能多的未知数:

  • 隔离建筑组件.
  • 删除非必要的,或可能有问题的(冲突的)元素.
  • 停用不同的应用程序模块.

删除生产,测试和开发之间的所有差异.使用相同的硬件.完全按照完全相同的步骤来设置计算机.一致性是关键.

记录

使用大量的日志记录来关联发生的时间事件.检查日志是否有任何明显的错误,时间问题等.

硬件

如果软件似乎没问题,请考虑硬件故障:

  • 物理网络连接是否牢固?
  • 有没有松动的电缆?
  • 芯片安装正确吗?
  • 所有电缆都有干净的连接吗?
  • 工作环境清洁无尘吗?
  • 是否有任何隐藏的设备或电缆被啮齿动物或昆虫损坏?
  • 驱动器上有坏块吗?
  • CPU风扇是否正常工作?
  • 主板可以为所有组件供电吗?(CPU,网卡,显卡,驱动器等)
  • 可能的电磁干扰是罪魁祸首?

主要用于嵌入式:

  • 供电绕过不足?
  • 板污染?
  • 焊点坏/回流不好?
  • 电源电压超出容差时CPU不复位?
  • 由于电源轨由I/O端口供电而没有完全放电,因此复位不良?
  • 闭锁?
  • 浮动输入引脚?
  • 逻辑电平上的噪声容限不足(有时为负)?
  • 时间余量不足(有时为负)?
  • 锡须
  • ESD损坏?
  • ESD干扰?
  • 芯片勘误表?
  • 接口误用(例如I2C板外或存在高功率信号)?
  • 比赛条件?
  • 假冒组件?

网络与本地

在本地运行应用程序(即不通过网络)会发生什么?其他服务器是否遇到同样的问题?数据库是远程的吗?你能使用本地数据库吗?

固件

在硬件和软件之间是固件.

  • 计算机BIOS是最新的吗?
  • BIOS电池有效吗?
  • BIOS时钟和系统时钟是否同步?

时间和统计

时间问题很难跟踪:

  • 什么时候出现问题?
  • 多久一次?
  • 当时正在运行的其他系统是什么?
  • 应用程序是否对时间敏感(例如,闰日或闰秒会导致问题)?

收集有关问题的硬数值数据.一开始可能出现随机的问题可能实际上有一种模式.

更换管理层

有时系统升级后会出现问题.

  • 什么时候问题首先开始?
  • 环境(硬件和软件)发生了什么变化?
  • 回滚到以前的版本后会发生什么?
  • 有问题的版本和好的版本之间存在什么差异?

图书馆管理

不同的操作系统有不同的方式来分配冲突的库:

  • Windows有DLL地狱.
  • Unix可以有许多破碎的符号链接.
  • Java库文件可以同样解决噩梦.

执行全新安装的操作系统,仅包括应用程序所需的支持软件.

Java的

确保每个库仅使用一次.有时,应用程序容器具有与应用程序本身不同的库版本.这可能无法在开发环境中进行复制.

使用MavenIvy等图书馆管理工具.

调试

对错误发生时触发通知(例如,日志,电子邮件,弹出窗口,寻呼机蜂鸣声)的检测方法进行编码.使用自动化测试将数据提交到应用程序中.使用随机数据.使用涵盖已知和可能的边缘情况的数据.最终这个bug应该重新出现.

睡觉

值得重申其他人所提到的:睡在上面.花时间远离问题,完成其他任务(如文档).远离电脑并进行锻炼.

代码审查

逐行浏览代码,并描述每行对自己,同事或橡皮鸭做的事情.这可能会导致对如何重现错误的见解.

宇宙辐射

宇宙射线可以翻转位.由于内存的现代错误检查,这不像过去的问题那么大.离开地球保护的硬件软件受到由于宇宙辐射的随机性而无法复制的问题.

工具

很少发生,但特别是对于利基工具(例如,遭受符号表溢出的C微控制器编译器).


Bri*_*new 13

如果它是一个GUI应用程序,那么观察客户生成错误(或尝试)是非常宝贵的.毫无疑问,他们正在做一些你从未猜到过他们正在做的事情(不是错误的,只是不同的).

否则,请将您的日志记录集中在该区域.记录大部分内容(您可以稍后将其删除)并让您的应用程序也转储其环境.例如机器类型,VM类型,使用的编码.

您的应用报告版本号,内部版本号等吗?您需要这个来确定您正在调试的版本(或不是!).

如果您可以检测您的应用程序(例如,如果您在Java世界中使用JMX),那么请检测相关区域.存储统计信息,例如请求+参数,时间等.利用缓冲区存储最后的'n'个请求/响应/对象版本/等等,并在用户报告问题时将其转储出去.


Kar*_*son 8

如果您无法复制它,您可能会修复它,但无法知道您已修复它.

我已经最好地解释了错误是如何被触发的(即使我不知道这种情况会如何发生),修复了这个问题,并确保如果错误再次出现,我们的通知机制会让未来的开发人员知道我希望我知道的事情.实际上,这意味着在可能触发错误的路径被越过时添加日志事件,并记录相关资源的度量标准.当然,确保测试能够很好地运用代码.

确定要添加的通知是可行性和分类问题.因此,首先要决定开发人员花在bug上的时间.如果不知道bug有多重要,就无法回答.

我有很好的结果(没有再出现,代码更好),而且很糟糕(花了太多时间没有修复问题,bug是否已经修复了).这就是估计和问题优先考虑的因素.

  • 我做过一次.我设法确定错误在哪里直到代码行,修复它,只是为了让它不被修复,因为有500行的第二个错误实例. (2认同)

Dav*_*vid 7

有时我只需坐下来研究代码,直到找到错误.试着证明这个bug是不可能的,在这个过程中你可能会弄清楚你可能会弄错的地方.如果你真的成功地说服自己这是不可能的,那么假设你搞砸了某个地方.

添加一堆错误检查和断言以确认或否定您的信念/假设可能会有所帮助.有些东西可能会失败,你永远不会想到.


dri*_*iis 6

这可能很困难,有时几乎不可能.但我的经验是,如果你花了足够的时间(如果花费的时间是值得的,那么你将迟早能够重现并修复bug)是另一回事.

一般建议可能有助于这种情况.

  • 如果可能,添加更多日志记录,以便下次出现错误时获得更多数据.
  • 询问用户是否可以复制错误.如果是的话,你可以让他们在看着他们的肩膀的同时复制它,并希望找出,是什么触发了这个bug.


Bob*_*ore 6

假设您已经添加了您认为有帮助的所有日志记录,但它没有帮助……我想到了两件事:

  1. 从报告的症状开始倒推。想一想..“如果我想产生所报告的症状,我需要执行哪些代码,我将如何实现它,以及我将如何实现它?” D 导致 C 导致 B 导致 A。接受这样的事实:如果错误不可重现,那么普通方法将无济于事。我不得不盯着代码好几个小时,不断地思考才能发现一些错误。通常情况下,事实证明这是非常愚蠢的事情。

  2. 记住鲍勃的调试第一定律:如果你找不到某些东西,那是因为你找错了地方:-)


Mic*_*Kay 6

思考。难的。把自己锁起来,不许任何打扰。

我曾经遇到过一个错误,其证据是损坏数据库的十六进制转储。指针链被系统地搞乱了。所有用户的程序以及我们的数据库软件在测试中都运行良好。我盯着它看了一周(这是一个重要的客户),在排除了数十种可能的想法后,我意识到数据分布在两个物理文件中,并且损坏发生在链跨越文件边界的地方。我意识到,如果备份/恢复操作在关键点失败,两个文件最终可能会“不同步”,恢复到不同的时间点。如果您随后在已经损坏的数据上运行客户的程序之一,它将准确地生成我所看到的打结的指针链。然后,我演示了一系列事件,准确地再现了损坏情况。


Mic*_*les 5

进行随机更改,直到有效果为止:-)