哪个层应该记录异常?

问题描述 投票:5回答:5

我有一个大型的整体应用程序,其中有四层可以满足特定的功能需求。

UI Layer-> Presentation Logic Layer-> Business Logic Layer-> Persistent Layer

一个用于呼叫流程的最小工作示例可以是,

class ProductViewController {
    func showProduct(list){
        // populate list in view
    }
}

class ProductPresenter {
    func sanitiseProduct(list){
        // apply presentation logic to list
        viewController.showProduct(list)
    }
}

class ProductService {
    func filerProducts(list){
        // apply filtering logic to list
        productPresenter.sanitiseProduct(list)
    }
}


class ProductDatabase {
    func retrieveProducts(){
        // retrieve raw product list
        productService.filerProducts(getAllProduct())
    }
}

现在,如果在流的任何层中发生任何异常(即query exception in Database layer),我已决定使用适当的[[TAG和info将其记录在每一层中,并返回上层进行传播,因此在调试时,每一层都可以使用适当的TAG过滤自己的日志,而无需查看其他层(即especially when different teams are responsible for different layers)。

[在审查时,我的一位同事评论说,在我的设计中,将为单个异常/错误复制日志,这可能会降低性能和内存。他的建议是将日志记录应用到特定异常(即query exception in Persistent Layer only)的一层中。但是,他建议继续将异常抛出到上层。

为了提高性能和内存,是否应该更改提供更好可维护性的日志记录方法?

应对这种情况的一般建议是什么?

logging design-patterns language-agnostic layer
5个回答
4
投票
答案是最可怕的。。取决于。我的意思是,如果您在性能或内存方面遇到问题,请确保一点点帮助。此外,重复的日志条目还会带来其他问题(例如每个团队都在查看与它们无关的日志条目/错误。花时间查看不相关的日志条目对于团队来说可能是浪费时间,即使他们可以看到标记非常快)。如果这是一个问题,则仅在源处进行记录可能是一件好事。

这就是说可维护性,这也是肯定的,对于大型单块应用程序,应该特别考虑它们,这种应用程序很可能会长期存在。我已经陷于使事情变得过于复杂的陷阱中,希望建立完美的解决方案,但是增加的复杂性使维护起来非常困难,以至于产生相反的效果,即变得非常糟糕。

因此,我的建议是,如果内存,性能等方面没有当前问题,那么对于长寿命的整体式应用程序来说,可维护性将胜出。但是我想这是答案,可能因开发人员而异。


1
投票
当您无法恢复时,请重新抛出异常,并在拦截器层(中间件)中捕获它。

否则,您可以遵循以下有趣的域模式:https://martinfowler.com/articles/domain-oriented-observability.html


0
投票
[我会同意其他海报,关于为维护性而过度设计的陷阱(或您将来会预见的任何其他原因)-对我来说,它很少能带来回报,这意味着无论如何我都必须重新设计一段时间。在大型企业应用程序上工作时,我确实使用了异常处理并在不同的层中进行了投递-具有相似分层体系结构的整体式应用程序,并且应用程序日志是分析的噩梦。

我将假定您没有使用异常来控制应用程序流,这是一种反模式。

根据我的经验,异常应由负责层处理,并根据与调用层的“合同”返回结果。这使得各层之间的接口非常紧密,并且当未遵循约定的接口时(例如,IllegalArgument),较低的层会引发异常。

如果处理异常不能导致有效的返回结果(例如,数据库连接丢失),则可以通过处理异常的层(例如,数据层抛出的“ DataAccessError”)来抛出通用的“层异常”。该异常仅应由可根据合同将结果返回到上层的层捕获,否则不应处理。在示例中,最终Presentation层将优雅地处理异常。

无论哪个层都在处理异常,它也应该记录该异常,并且在您这种情况下,您只需要一种在日志中区分源于哪一层日志行的方法,因此对于上面的示例,日志看起来像这样……] >

[PRESENTATION] Error displaying Product Info: DataAccessLayerError - Error fetching Product info for ID 123. ... ... [DATA] Error fetching Product info for ID 123: /stack trace of caught DB Connection Error/

这与打印Thread Context(或您的日志记录框架中的等效方法)相结合,将更容易跟踪日志文件中的错误。 

您可以尝试遵循此域格式https://martinfowler.com/articles/domain-oriented-observability.html除了无法维护的代码外,通常不能导致良好的性能提升。

理想情况下,答案是Business Logic Layer。至于Persistence Layer,可以在Business Logic Layer处捕获异常。

此外,Presentation Layer的工作是从UI Layer中获取数据,反序列化并将其发送到Business Logic Layer,然后从Business Logic Layer中获取数据进行序列化并将其发送到UI Layer

OR

也取决于软件的体系结构。您还可以在每个层中记录错误,并使用唯一的标识符来查找特定的操作。例如,使用HTTP请求的软件应在每个日志语句中使用唯一的requestId来标识请求的所有操作,对于消息系统(排队系统),可以类似地使用messageId来标识操作的日志。

0
投票
您可以尝试遵循此域格式https://martinfowler.com/articles/domain-oriented-observability.html除了无法维护的代码外,通常不能导致良好的性能提升。

0
投票
理想情况下,答案是Business Logic Layer。至于Persistence Layer,可以在Business Logic Layer处捕获异常。
© www.soinside.com 2019 - 2024. All rights reserved.