为啥“log and throw”被认为是一种反模式? [关闭]

Posted

技术标签:

【中文标题】为啥“log and throw”被认为是一种反模式? [关闭]【英文标题】:Why is "log and throw" considered an anti-pattern? [closed]为什么“log and throw”被认为是一种反模式? [关闭] 【发布时间】:2011-10-02 04:03:39 【问题描述】:

这个问题是由围绕this article 的讨论引发的,我没有得到任何好的答案。

如果你不能以其他方式处理它,为什么要记录你的异常然后重新抛出它(当然保留原始堆栈跟踪)是一个坏主意?

【问题讨论】:

尝试在softwareengineering.stackexchange.com上搜索答案 【参考方案1】:

我认为答案很大程度上是因为如果你不能处理它,你为什么要抓住它?如果他们认为它值得记录,为什么不让任何可以处理它的人(或者除了处理它别无选择的人)记录它?

如果您捕获并记录它并重新抛出它,那么上游代码将无法知道您已经记录了异常,因此相同的异常可能会被记录两次。或者更糟糕的是,如果所有上游代码都遵循相同的模式,则异常可能会被记录任意次数,对于决定捕获它、记录它然后再次抛出它的代码中的每个级别一次。

还有一些人可能会争辩说,由于抛出和捕获异常是相对昂贵的操作,所有这些捕获和重新抛出都不会帮助您提高运行时性能。它在简洁性或可维护性方面也对您的代码没有帮助。

【讨论】:

记录并重新抛出远征的原因应该是缩小原因并记录特定消息。 Answer : 在堆栈中的当前点可能有有用的调试信息在堆栈跟踪中的其他点不可用 如果新异常对更多信息或更具体的帮助更有帮助,则捕获和重新抛出有时会有所帮助。 扩展@rtconner 评论的内容:在异步代码中,捕手可能没有投掷者可用的上下文。 这不是为什么您通常可以在再次抛出异常或将它们包装到另一个异常之前将信息附加到异常吗?【参考方案2】:

Log-and-throw 是一个很好的模式,如果实体捕获并重新抛出异常有理由相信它包含不会被进一步记录到调用堆栈上的信息——至少不是以最理想的方式。发生这种情况的几个原因:

    异常可能会在应用层边界被捕获并重新抛出,并且可能包含特权信息。数据库层允许异常说,例如“尝试将重复键 'fnord' 添加到字段 'users'”以到达外部应用程序层(这可能反过来将其暴露给用户),但是对于数据库的内部部分抛出这样的异常和应用程序接口来捕获它,安全地记录它,并重新抛出一个描述性稍差的异常。 该异常可能是外层可能期望在不记录的情况下处理的异常,但内层可能知道外层不知道的某些内容,这表明记录可能有用。作为一个粗略的例子,一个中间应用层可能被编程为尝试连接到一个服务器,如果这不起作用,请尝试另一个。当服务器停机进行维护时,用“连接失败”消息淹没应用程序的日志可能没有帮助,特别是因为从应用程序的角度来看,一切正常。将有关连接失败的信息转发到与服务器关联的日志记录资源可能很有用,然后可以过滤日志以生成服务器何时启动和关闭的报告,而不是每次连接尝试的日志.

【讨论】:

#1 确实是一个明智的一般用例,但是 OP 明确询问“重新抛出它(当然保留原始堆栈跟踪)”,所以 #1 不是正确的答案。 @GeoffreyZheng:这取决于安全地记录原始堆栈跟踪是否算作“保留”。 关于#1:暴露异常内容(如在 UI 上显示e.getMessage()/stacktrace,以及将其作为 REST 响应发送)应视为漏洞本身,因为运行时异常可能包含任何类型的敏感信息。关于#2:您可以重新抛出异常,添加您希望客户知道的所有信息(+根本原因),无需记录任何内容。 @NikitaBosik:无论是否应该在客户端公开异常,这样做的应用程序都足够普遍,以至于“深度安全”原则建议应该清除异常消息中的敏感信息。此外,如果外层不希望丢弃特定类型的异常而不记录它或将信息转发给可能感兴趣的外部实体,那么让中间层添加外层将忽略的信息将无济于事任何东西。【参考方案3】:

我想最简单的原因是您通常会有一个***处理程序为您执行此操作,因此无需使用此异常处理来污染代码。

横切关注点的论点基本上是浪费时间处理与您无关的错误。最好让错误在调用堆栈中冒泡,直到找到合适的处理程序。

在我看来,您应该捕获异常的唯一时间是您可以对结果做一些有用的事情。仅仅为了记录而捕获是没有用的,因为您可以进一步集中该工作。

【讨论】:

我同意您应该有一个***处理程序为您执行此操作。但在我看来,***处理程序应该是“记录并抛出”。所以争论是围绕在哪个点“记录并抛出”,而不是根本不这样做?!? @Manu,我想重点是,如果它是单个处理程序(集中式),那很好。如果您要复制代码,那就不好了。我认为没有比这更多的了! @Manu - 在这种情况下,***处理程序会抛出什么?在我看来,如果有东西可以扔给它,那么它就不是真正的***处理程序。而且您绝对不想将异常重新抛出到运行时环境本身。这将使大多数应用程序崩溃。 @aroth:我明白了,您说的是“记录并处理”(如果您是***处理程序)或“不记录并抛出(或处理其他情况)”如果你不是。感谢您指出这一点。【参考方案4】:

IMO log and throw 明显违反了最小意外原则。

如果异常在调用堆栈的更上层得到正确处理,则可能根本不值得输入错误日志。然后发现错误日志条目令人困惑。

【讨论】:

非错误日志呢? @SuZhang 我不太明白你的问题。如果没有错误,则没有什么可抛出的。当然,您可以并且应该编写非错误日志。

以上是关于为啥“log and throw”被认为是一种反模式? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

关于“贫血领域模型”被认为是反模式[闭合]的具体例子

计算行数或枚举行号,以便我可以遍历它们 - 为啥这是一种反模式?

上下文模式?为啥 Core Data 需要它?

为啥单身人士被认为是一种不好的做法? [复制]

为啥关联规则学习被认为是一种监督学习方法?

为啥捕获 RuntimeException 不被认为是一种好的编程习惯? [关闭]