我应该只捕获exception才能记录它们吗?

我是否应该捕获日志记录的exception?

 public foo(..)
 {
   尝试
    {
      ...
    } catch(Exception ex){
      Logger.Error(前);
     扔;
    }
 }

如果我在每个层(DataAccess,Business和WebService)中都有这个,这意味着多次记录exception。

如果我的图层在单独的项目中并且只有公共接口中有try / catch,那么这样做是否有意义? 为什么? 为什么不? 我可以使用不同的方法吗?

当然不。 你应该找到处理exception的正确位置(实际上做一些事情,比如catch-and-not-rethrow),然后记录它。 当然,您可以而且应该包括整个堆栈跟踪,但是根据您的建议,将使用try-catch块来丢弃代码。

除非您要更改exception,否则只应记录要处理错误的级别,而不是重新抛出它。 否则,您的日志只会有一堆“噪音”,记录3条或更多相同的消息,每层一次。

我的最佳做法是:

  1. 只在公共方法中尝试/捕获(一般情况下;显然如果你要捕获一个特定的错误,你会在那里检查它)
  2. 只有在压缩错误并重定向到错误页面/表单之前才能登录UI层。

一般的经验法则是,如果你真的可以做一些事情,你只能抓住一个例外。 因此,在业务或数据层,您只能在以下情况中捕获exception:

try { this.Persist(trans); } catch(Exception ex) { trans.Rollback(); throw ex; } 

我的业务/数据层尝试保存数据 – 如果生成exception,则回滚任何事务并将exception发送到UI层。

在UI层,您可以实现一个公共exception处理程序:

Application.ThreadException + = new ThreadExceptionEventHandler(Application_ThreadException);

然后处理所有exception。 它可能会记录exception,然后显示用户友好的响应:

  static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { LogException(e.Exception); } static void LogException(Exception ex) { YYYExceptionHandling.HandleException(ex, YYYExceptionHandling.ExceptionPolicyType.YYY_Policy, YYYExceptionHandling.ExceptionPriority.Medium, "An error has occurred, please contact Administrator"); } 

在实际的UI代码中,如果要执行不同的操作,可以捕获单个exception – 例如显示不同的友好消息或修改屏幕等。

另外,作为提醒,总是尝试处理错误 – 例如除以0 – 而不是抛出exception。

最好的做法是翻译例外 。 不要只记录它们。 如果您想知道抛出exception的具体原因,请抛出特定的exception:

 public void connect() throws ConnectionException { try { File conf = new File("blabla"); ... } catch (FileNotFoundException ex) { LOGGER.error("log message", ex); throw new ConnectionException("The configuration file was not found", ex); } } 

使用您自己的exception来包装inbuildexception。 这样,您可以在捕获exception时区分已知错误和未知错误。 如果您有一个方法可以调用其他方法,这些方法可能会引发激活以对预期和意外故障做出反应,这将非常有用

您可能希望查找标准exception处理样式,但我的理解是:在可以向exception添加额外详细信息的级别处理exception,或者在向用户显示exception的级别处理exception。

在你的例子中你除了捕获exception,记录它并再次抛出它之外什么都不做。为什么不只是在最高级别用一次try / catch而不是在每个方法中捕获它,如果你正在做的就是记录它?

我只会在该层处理它,如果您要在再次抛出exception之前向exception添加一些有用的信息 – 将exception包装在您创建的新exception中,该exception除了低级exception文本之外还有其他有用的信息没有一些背景..

有时您需要记录处理exception时不可用的数据。 在这种情况下,只记录以获取该信息是合适的。

例如(Java伪代码):

 public void methodWithDynamicallyGeneratedSQL() throws SQLException { String sql = ...; // Generate some SQL try { ... // Try running the query } catch (SQLException ex) { // Don't bother to log the stack trace, that will // be printed when the exception is handled for real logger.error(ex.toString()+"For SQL: '"+sql+"'"); throw ex; // Handle the exception long after the SQL is gone } } 

这类似于追溯日志记录(我的术语),您可以在其中缓冲事件日志,但除非存在触发事件(例如抛出exception),否则不会写入事件。

如果您需要记录所有exception,那么这是一个很棒的主意。 也就是说,没有其他原因记录所有exception并不是一个好主意。

您可能希望记录最高级别,通常是您的UI或Web服务代码。 多次记录是一种浪费。 此外,当您查看日志时,您想要了解整个故事。

在我们的一个应用程序中,我们的所有页面都是从BasePage对象派生的,并且该对象处理exception处理和错误记录。

如果这是它唯一做的事情,我认为最好从这些类中删除try / catch,并将exception提升到负责处理它们的类。 这样,每个exception只能获得一个日志,为您提供更清晰的日志,甚至您可以记录堆栈跟踪,这样您就不会错过发生exception的位置。

我的方法是仅在处理程序中记录exception。 可以说是“真正的”处理程序。 否则,日志将很难阅读,代码结构化程度较低。

这取决于exception:如果这实际上不应该发生,我肯定会记录它。 另一方面:如果你期望这个例外,你应该考虑应用程序的设计。

无论哪种方式:您至少应该尝试指定要重新抛出,捕获或记录的exception。

 public foo(..) { try { ... } catch (NullReferenceException ex) { DoSmth(e); } catch (ArgumentExcetion ex) { DoSmth(e); } catch (Exception ex) { DoSmth(e); } } 

您将需要登录层边界。 例如,如果您的业务层可以部署在n层应用程序中的物理上独立的计算机上,那么以这种方式记录和抛出错误是有意义的。

通过这种方式,您可以在服务器上记录exception日志,而无需在客户端计算机上查找发生的情况。

我在使用Remoting或ASMX Web服务的应用程序的业务层中使用此模式。 使用WCF,您可以使用附加到ChannelDispatcher的IErrorHandler(完全是另一个主题)来拦截和记录exception – 因此您不需要try / catch / throw模式。

您需要制定处理exception的策略。 我不建议捕获和重新抛出。 除了多余的日志条目之外,它还使代码更难阅读。 考虑在构造函数中写入exception的日志。 这将为您要恢复的exception保留try / catch; 使代码更容易阅读。 要处理意外或不可恢复的exception,您可能需要在程序最外层附近的try / catch来记录诊断信息。

顺便说一句,如果这是C ++你的catch块正在创建一个exception对象的副本,这可能是其他问题的潜在来源。 尝试捕获对exception类型的引用:

   catch(const Exception&ex){...}

此软件工程无线电播客是error handling最佳实践的非常好的参考。 实际上有2个讲座。