何时抛出异常,何时记录日志?

3
我是一位能够帮助翻译文本的助手。

我有一个三层结构:
1. 展示层
2. 业务层
3. 数据层
展示层通过服务门面与业务层交互。现在我困惑于应该在哪里抛出异常、在哪里记录异常以及在哪里捕获并忽略异常。目前,在记录日志后,我在我的展示层中忽略异常,而在其他地方,我在记录日志和抛出异常。这导致异常被记录了三次。虽然这不是一个巨大的问题,但我想知道最佳实践是什么。

例如: 展示层代码:

try 
{
  UserService.GetAllUsers() ;
}
catch(Exception ex )
{
  Logger.log(ex) // exception gets logged here
  // redirect to a friendly user error page 
}

用户服务层代码

try
{
  IUserDAO userDAO = ServiceRegistry.GetRegistry().GetDAOFactory().GetUserDAO() ;
  return userDao.GetAllUsers() ;
}
catch ( Exception ex)
{
  Logger.log(ex) ;  // and here !
  throw;
}

DAO层代码

try
{
  // All db interaction code 
}
catch(Exception ex)
{
  Logger.log(ex) //and here !!
  throw ;
}

这些都在同一台物理机器上吗?还是你有一个服务器和客户端?在我们的应用程序中,通常会在所有物理机器上尝试记录一次错误消息... - Fortega
1
目前所有的这些都在同一台物理机器上,但将来我们可能会把它们放在不同的物理机器上。那会有影响吗? - NM.
我认为是这样的。如果服务器上出现异常,您希望在那里记录它,但也要在调用导致异常发生的方法的客户端上记录它,以便在两个位置都可以跟踪错误。看起来可能会记录很多/太多,但由于此原因导致性能或存储问题的可能性非常小,因此我建议保留它... - Fortega
5个回答

4

在try-catch块中放置每个代码片段绝对是不必要的。例如,如果在您的“DAOLayer”中发生异常,则日志文件将包含相同的异常3次...

请记住异常的黄金法则 - 异常应该是异常的!这通常意味着您只应捕获能够处理的异常 - 所有其他异常都应忽略 - 更高级别的处理程序应处理这些异常。

如果您担心未处理的异常会使应用程序崩溃(这是正确的),则应查看.Net为处理未处理异常而公开的2个事件。第一个是AppDomain.CurrentDomain.UnhandledException,第二个是Application.ThreadException(位于Windows.Forms命名空间中)。


1

我真的看不出来你为什么要记录异常并重新抛出它。无论哪个进程最终吞噬它都可以进行日志记录。如果您想记录该信息,可以简单地使用ex.StackTrace获取调用堆栈。

通常,当导致异常的问题不是代码所在级别可以解决的问题时,重新抛出异常是您要执行的操作。您通常会使用更具体的catch块来捕获这些异常并做出适当的响应(例如,如果由于网络超时而引发异常,则可以重试连接或尝试连接到备份服务器)。您需要在修复问题的点记录异常并继续执行。

如果在获取异常时您无法采取任何措施,那么只有在不能指望调用堆栈中的后续内容为我处理日志记录时,我才会费心地捕获和记录它。否则,它只会创建一个相当无意义的重复消息。


层的客户端可能会更改,如果我没有在我的层中记录登录信息,我就有点依赖客户端来记录登录信息,如果他们不这样做...我就会陷入麻烦。 - NM.
1
那是记录在多个地方的明智理由 - 因为您不能指望客户端处理日志记录。但应分别捕获可解决的错误。 - Adam Luchjenbroers

1

当发生异常情况时,您应该在任何层面上抛出异常...如果您预计某些错误条件会经常出现,请为它们编写代码-向用户显示错误并提供修复错误的方法。

记录所有异常,没有例外!拥有数据很好,如果您遵循我的建议,您不会有太多这样的异常。

您绝不能吞噬异常。请参见上文。否则,您如何知道事情出了问题?


有时候吞掉异常而不是让应用程序失败可能是正确的选择。这是在权衡正确性和健壮性,有时候健壮性更重要。 - Adam Luchjenbroers
始终记录日志。根据要求,您可以决定是否传播异常。 - Oded

1

我常做的是为每个级别创建一个异常,并将异常包装并传递,如果上一层无法处理该异常,则继续向上传递。

例如,如果您尝试更新数据库,但主数据库已关闭,则可能只需要转到辅助数据库,因此您可以尝试这样做,如果成功则记录日志但不继续传递。

我往往会传递无法处理的异常,直到达到顶层。 在那里,对于某些错误,请将其传递给客户端,如果用户能够采取某些措施来解决异常问题,否则请记录并忽略。

如果出现像内存不足之类的情况,请通知用户并准备优雅地退出应用程序崩溃之前。


0

与其将异常包装在自定义异常中或仅依赖于 StackTrace 在记录顶层异常时提供所有所需信息,您可以使用 ex.Data 在将异常传递到上层之前添加有关异常的更多信息,例如 ex.Data.Add("filename", filename)。然后,您的日志记录代码可以转储所有这些附加属性。这可能为您提供足够的信息,以了解为什么引发异常并重现它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接