提问人:sym er 提问时间:11/2/2023 更新时间:11/2/2023 访问量:40
收集 Java 中未捕获异常的指标
collect metrics for uncaught exceptions in Java
问:
我想收集那些未捕获的异常的指标,我是通过 java 代理来完成的,那么我应该增强哪个类呢? 如果我想收集这些异常,我可以只是增强异常的构造函数,但是我如何选择那些未捕获的异常?
答:
Thread.setUncaughtExceptionHandler
Thread.setUncaughtExceptionHandler, new Thread.UncaughtExceptionHandler() {
void uncaughtException(Thread t, Throwable e) {
// record information about uncaught Exceptions and Errors here.
}
});
评论
真的不可能。
问题出在定义上。定义“未捕获的异常”。
专门的
从技术上讲,没有这样的事情。最终,异常总是被某些东西捕获。他们冒泡堆栈,立即结束方法,递归地应用该原则(现在结束这个方法,回到堆栈上的方法。现在结束那个,再往上回到方法一个。不休。或者直到我们击中一个接球块,你总是会的)。
如果有必要,线程本身会抓住它。然后,它调用未捕获的异常处理程序。您可以使用 进行配置。无需使用代理来调用该方法。Thread.setUncaughtExceptionHandler
但是,注入一些简单的东西,比如说,应用程序服务器或 Web 服务器,通常它们的“端点运行器”(框架中调用代码的东西)会捕获所有内容。
那么,你如何定义“未被抓住”呢?冒泡到 Web 服务器端点运行程序的异常是否算作“未捕获”?
如果你说“是的,那是未被抓住的”,你有几个问题:
您需要特定的知识并修改 Web 框架才能弄清楚这一点。你必须为每个 Web 框架编写它,或者至少为堆栈使用的每个 appserver 类东西定制你的“未捕获的异常计数器”。
这还将计算由发送方引起的 IOException,因为他们在发送 HTTP 标头和 ServletExceptions 时中途挂断了连接,即设计为由 Web 服务器端点运行程序处理的事情。我认为这个“未捕获的异常计数系统”的重点是找到并消除这些东西,但随后你就会遇到误报问题。这些异常绝对不应该被“处理”——当前正在发生的事情(它们最终出现在处理它们的 Web 服务器运行器上)是正确的。
如果你说“不,这意味着它们被处理了”,那么你的应用是无用的,因为这意味着一切都被处理了。因为这些端点运行器捕获了 Throwable。(这样做是正确的)。
因此,技术方法是不可行的。除非您只想停止堆栈跟踪显示在 sysout 上。然后,只需使用 .JVM 以未捕获的异常处理程序开始,该处理程序仅将异常类型、消息、跟踪和因果链输出到 。你可以用一个做其他事情的人覆盖它,没问题。作为你方法中的第一件事。无需为代理商而烦恼。Thread.setUncaughtExceptionHandler
System.err
void main()
务实
与其试图关注某种技术定义,不如谈谈“未处理的异常”的实际含义,它通常是:代码应该处理但未处理的异常。
问题是,作为一个概念,它完全不受任何技术上可以测量的东西的束缚。例如,采用以下代码:
public void saveGame() {
try {
Files.write("symersAwesomeGame001.sav", gameState.asBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
如果我带着麦克风去参加 Java 会议,向他们展示上面的代码,然后问:“那么,你说什么?这段代码的作者是否处理过 I/O 异常?“,绝大多数受访者都会给出正确答案。这是不的 - 这根本不合适。
如果目标是找到异常处理不正确的地方,那么这正是您想要找到的那种东西。但这与技术定义相反:例外正在被抓住。但这就是问题所在:它被抓住了,但没有正确处理。此处的正确移动可能会使方法声明为 ,或者可能)。如果做不到这一点,catch 块应为 .saveGame()
throws IOException
throws SaveException
throw new RuntimeException("unhandled", e);
尝试编写一个代理来捕获这些东西在某种程度上是可能的,如果你假设“只打印堆栈跟踪的捕获块是错误的,句号”。你可以通过解析类 defs 来扫描它(扫描字节码:通过 ASM 或 bytebuddy 或其他一些字节码内省工具进行抛出)。
但是,这项工作更适合源代码级别的 linting。应设置一个 linter 规则,以禁止仅 .这样做的一个好处是,您可以设置一些选择退出 linter 的评论 - 对于极少数情况,什么是经过深思熟虑的正确答案(很少见,但存在的情况,尽管很少见,这样做是正确的)。e.printStackTrace()
e.printStackTrace();
评论
Thread.setUncaughtExceptionHandler