我应该捕获异常才能记录它们吗?

时间:2008-09-18 18:44:31

标签: c# logging exception-handling

我是否应该捕获用于记录目的的异常?

public foo(..)
{
   try
   {
     ...
   } catch (Exception ex) {
     Logger.Error(ex);
     throw;
   }
}

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

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

16 个答案:

答案 0 :(得分:35)

绝对不是。您应该找到处理异常的正确位置(实际执行某些操作,例如catch-and-not-rethrow),然后记录它。您当然可以并且应该包括整个堆栈跟踪,但是根据您的建议会使用try-catch块来丢弃代码。

答案 1 :(得分:18)

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

我的最佳做法是:

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

答案 2 :(得分:9)

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

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

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

在UI层,您可以实现一个常见的异常处理程序:

Application.ThreadException + = new ThreadExceptionEventHandler(Application_ThreadException);

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

    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代码中,如果要执行不同的操作,可以捕获个别异常 - 例如显示不同的友好消息或修改屏幕等。

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

答案 3 :(得分:2)

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

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);
   }
}

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

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

我只会在该层处理它,如果您要在再次抛出异常之前向异常添加一些有用的信息 - 将异常包装在您创建的新异常中,该异常包含超出低级异常文本的有用信息,这通常意味着没有一些背景的人很少。

答案 6 :(得分:1)

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

例如(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
    }
}

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

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

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

答案 12 :(得分:0)

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

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

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

答案 13 :(得分:0)

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

BTW,如果这是C ++,你的catch块就会创建一个异常对象的副本,这可能是其他问题的潜在来源。尝试捕获对异常类型的引用:

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

答案 14 :(得分:0)

This软件工程广播播客是错误处理最佳实践的非常好的参考。实际上有2个讲座。

答案 15 :(得分:0)

一般来说这是不好的做法,除非您出于非常具体的原因需要登录。

对于一般的日志异常,应该在根异常处理程序中处理。