Java中崩溃报告的策略/技术

时间:2009-08-21 16:03:56

标签: java error-handling crash

我正在开发一个新的Java桌面应用程序,并希望包含一个崩溃报告工具 - 你知道那种事情 - 程序崩溃,弹出框要求用户点击好发送它等等。

我很清楚如何将错误发送回我们的服务器 - 可能是通过一个简单的Web服务。我更不确定的是如何实现捕获故障的机制?我会欢迎任何已经实施过类似建议的人的建议。

6 个答案:

答案 0 :(得分:7)

有一个命令行选项可以让JVM在JVM与内存转储崩溃后运行批处理文件。您所要做的就是创建一个执行错误报告的外部程序,然后使用JVM选项使用您创建的实用程序在电子邮件中发送核心转储。

-XX:-HeapDumpOnOutOfMemoryError -XX:OnError="<cmd args>;<cmd args>"

答案 1 :(得分:5)

使用Thread.setUncaughtExceptionHandler和静态Thread.setDefaultUncaughtExceptionHandler来(尝试)向您的日志记录系统报告异常。

答案 2 :(得分:2)

我看到三个案例:

  1. 灾难。 JVM本身要么死了,要么死了。您不能假设您的任何代码都能够工作 - 例如,您无法分配任何内存。因此,在这种情况下,您无法合理地希望能够发送任何诊断信息。您可以期待的最好的方法是在死亡程序的灰烬中留下一些诊断信息,例如核心转储。

    在这种情况下,您可以在启动新运行时查找此类碎片并建议用户收集它,或者更多的努力尝试自己组装诊断包。

  2. 低级应用程序代码不会捕获异常,可能是RunTime异常,例如NullPointer异常。在这种情况下,你可以在你的主要(假设你有一个)你可以捕获异常,并希望你的Crash Reporter代码可以工作。 将异常及其堆栈跟踪传递给Crash Reporter。

  3. 你的低级代码捕捉到了一些非常不健康的东西。不足以终止流程,但值得报告。在这里,您不仅可以获得例外,还可以获得其他上下文信息。我们还有更多要发送给Crash Reporter。

答案 3 :(得分:2)

使用日志记录。通用模式的工作方式如下:

  • 创建一个将错误消息发送到服务器的appender(大多数日志记录框架支持通过邮件甚至JDBC传输日志消息的appender)。如果没有现有的appender,他们会举例说明如何做到这一点。
  • 将该appender添加到根记录器并将其阈值设置为ERROR
  • 发现异常时记录错误。然后,日志框架将为您进行管道处理。

答案 4 :(得分:0)

我不知道这是否是Java目前提供的最佳功能,但这是我一段时间所做的。

首先,所有可能崩溃的有趣活动都是通过命令模式发送的。这个应用程序包括通过互联网访问应用程序服务器,所以很多可能会出错。命令调度程序捕获了异常并向用户显示了相应的结果(通常显示错误对话框,然后是关闭和发送有关崩溃的电子邮件)。

其次,在Swing中使用自定义事件队列来捕获事件线程上发生的任何异常。我希望Java现在有更好的解决方案,但基本上当发生异常时你必须检查你的代码是否涉及,否则一些Swing错误可能会使你的应用程序崩溃,这是不愉快的。当然,必须检查递归(当您尝试向用户显示消息时,崩溃会一遍又一遍地重复)。

顺便说一下,大多数崩溃都会让你的JVM继续运行,包括内存不足错误,足以在大多数情况下发送电子邮件,因为内存不足错误后错误通常会释放出足够的堆栈(和因此堆)允许进一步的垃圾收集并让您的代码生效。但在这种情况下你仍然应该迅速退出。 IDEA在出现内存不足错误后继续运行,但通常运行不正常。他们最好离开,IMO。

使用以下和子类EventQueue推送新队列以链接您的行为。

 Toolkit.getDefaultToolkit().getSystemEventQueue().push(newQueue);

答案 5 :(得分:0)

一种选择是使用BugSense。它针对移动应用程序崩溃报告,但API声明它可用于任何类型的崩溃报告。从我读过的内容中可以很简单,所有需要做的就是创建一个包含所有值的简单POST请求。

{
   "client": {
      "name": "bugsense-android", // Obligatory
      "version": "0.6"
   },
   "request": {
      "remote_ip": "10.0.0.1",
      "custom_data": {
         "key1": "value1",
         "key2": "value2"
      }
   },
   "exception": {
      "message": "java.lang.RuntimeException: exception requested", // Obligatory
      "where": "MainActivity.java:47", // Obligatory
      "klass": "java.lang.RuntimeException", // Type of exception
      "backtrace": "java.lang.RuntimeException: exception requested\r\nat com.sfalma.trace.example.MainActivity$1.onClick(MainActivity.java:47)\r\nat android.view.View.performClick(View.java:2408)\r\nat android.view.View$PerformClick.run(View.java:8816)\r\nat android.os.Handler.handleCallback(Handler.java:587)\r\nat android.os.Handler.dispatchMessage(Handler.java:92)\r\nat android.os.Looper.loop(Looper.java:123)\r\nat android.app.ActivityThread.main(ActivityThread.java:4627)\r\nat java.lang.reflect.Method.invokeNative(Native Method)\r\nat java.lang.reflect.Method.invoke(Method.java:521)\r\nat com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)\r\nat com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)\r\nat dalvik.system.NativeStart.main(Native Method)\\n" // Obligatory
   },
   "application_environment": {
      "phone": "android", // Device model (could be PC or Max) Obligatory
      "appver": "1.2", // Obligatory
      "appname": "com.sfalma", // Obligatory
      "osver": "2.3", // Obligatory
      "wifi_on": "true",
      "mobile_net_on": "true",
      "gps_on": "true",
      "screen_dpi(x:y)": "120.0:120.0",
      "screen:width": "240",
      "screen:height": "400",
      "screen:orientation": "normal"
   }
}

你可以read more about it here