收集 Java 中未捕获异常的指标

collect metrics for uncaught exceptions in Java

提问人:sym er 提问时间:11/2/2023 更新时间:11/2/2023 访问量:40

问:

我想收集那些未捕获的异常的指标,我是通过 java 代理来完成的,那么我应该增强哪个类呢? 如果我想收集这些异常,我可以只是增强异常的构造函数,但是我如何选择那些未捕获的异常?

Java 异常 代理

评论

0赞 ControlAltDel 11/2/2023
Thread.setUncaughtExceptionHandler

答:

1赞 ControlAltDel 11/2/2023 #1

Thread.setUncaughtExceptionHandler

Thread.setUncaughtExceptionHandler, new Thread.UncaughtExceptionHandler() {
  void uncaughtException(Thread t, Throwable e) {
    // record information about uncaught Exceptions and Errors here.
  }
});

评论

0赞 sym er 11/2/2023
谢谢你的建议!
0赞 rzwitserloot 11/2/2023 #2

真的不可能。

问题出在定义上。定义“未捕获的异常”。

专门的

从技术上讲,没有这样的事情。最终,异常总是被某些东西捕获。他们冒泡堆栈,立即结束方法,递归地应用该原则(现在结束这个方法,回到堆栈上的方法。现在结束那个,再往上回到方法一个。不休。或者直到我们击中一个接球块,你总是会的)。

如果有必要,线程本身会抓住它。然后,它调用未捕获的异常处理程序。您可以使用 进行配置。无需使用代理来调用该方法。Thread.setUncaughtExceptionHandler

但是,注入一些简单的东西,比如说,应用程序服务器或 Web 服务器,通常它们的“端点运行器”(框架中调用代码的东西)会捕获所有内容。

那么,你如何定义“未被抓住”呢?冒泡到 Web 服务器端点运行程序的异常是否算作“未捕获”?

如果你说“是的,那是未被抓住的”,你有几个问题:

  1. 您需要特定的知识并修改 Web 框架才能弄清楚这一点。你必须为每个 Web 框架编写它,或者至少为堆栈使用的每个 appserver 类东西定制你的“未捕获的异常计数器”。

  2. 这还将计算由发送方引起的 IOException,因为他们在发送 HTTP 标头和 ServletExceptions 时中途挂断了连接,即设计为由 Web 服务器端点运行程序处理的事情。我认为这个“未捕获的异常计数系统”的重点是找到并消除这些东西,但随后你就会遇到误报问题。这些异常绝对不应该被“处理”——当前正在发生的事情(它们最终出现在处理它们的 Web 服务器运行器上)是正确的。

如果你说“不,这意味着它们被处理了”,那么你的应用是无用的,因为这意味着一切都被处理了。因为这些端点运行器捕获了 Throwable。(这样做是正确的)。

因此,技术方法是不可行的。除非您只想停止堆栈跟踪显示在 sysout 上。然后,只需使用 .JVM 以未捕获的异常处理程序开始,该处理程序仅将异常类型、消息、跟踪和因果链输出到 。你可以用一个做其他事情的人覆盖它,没问题。作为你方法中的第一件事。无需为代理商而烦恼。Thread.setUncaughtExceptionHandlerSystem.errvoid main()

务实

与其试图关注某种技术定义,不如谈谈“未处理的异常”的实际含义,它通常是:代码应该处理但未处理的异常。

问题是,作为一个概念,它完全不受任何技术上可以测量的东西的束缚。例如,采用以下代码:

public void saveGame() {
  try {
    Files.write("symersAwesomeGame001.sav", gameState.asBytes());
  } catch (IOException e) {
    e.printStackTrace();
  }
}

如果我带着麦克风去参加 Java 会议,向他们展示上面的代码,然后问:“那么,你说什么?这段代码的作者是否处理过 I/O 异常?“,绝大多数受访者都会给出正确答案。这是的 - 这根本不合适。

如果目标是找到异常处理不正确的地方,那么这正是您想要找到的那种东西。但这与技术定义相反:例外正在被抓住。但这就是问题所在:它被抓住了,但没有正确处理。此处的正确移动可能会使方法声明为 ,或者可能)。如果做不到这一点,catch 块应为 .saveGame()throws IOExceptionthrows SaveExceptionthrow new RuntimeException("unhandled", e);

尝试编写一个代理来捕获这些东西在某种程度上是可能的,如果你假设“只打印堆栈跟踪的捕获块是错误的,句号”。你可以通过解析类 defs 来扫描它(扫描字节码:通过 ASM 或 bytebuddy 或其他一些字节码内省工具进行抛出)。

但是,这项工作更适合源代码级别的 linting。应设置一个 linter 规则,以禁止仅 .这样做的一个好处是,您可以设置一些选择退出 linter 的评论 - 对于极少数情况,什么是经过深思熟虑的正确答案(很少见,但存在的情况,尽管很少见,这样做是正确的)。e.printStackTrace()e.printStackTrace();

评论

0赞 ControlAltDel 11/2/2023
次要观点:我喜欢抛出 Error 而不是 RuntimeException,因为我看到 Error 表示“我们检测到问题,并且它不可恢复”,而 RuntimeException 对我来说表示需要在代码中修复的现有问题......我是怎么做到的:-)
0赞 sym er 11/2/2023
感谢您的建议和详细解释!这对我非常有帮助。但是,我无法直接扫描代码,因为我想使用 Java 代理增强这些应用程序。因此,它必须是非侵入性的。阅读您的评论后,我认为最好收集所有异常。