Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我是否应该捕获异常以记录它们?_C#_Logging_Exception Handling - Fatal编程技术网

C# 我是否应该捕获异常以记录它们?

C# 我是否应该捕获异常以记录它们?,c#,logging,exception-handling,C#,Logging,Exception Handling,我应该捕获用于日志记录的异常吗 public foo(..) { try { ... } catch (Exception ex) { Logger.Error(ex); throw; } } 公共食品(……) { 尝试 { ... }捕获(例外情况除外){ 记录器错误(ex); 投掷; } } 如果在我的每一层(DataAccess、Business和WebService)中都有这样的功能,这意味着会记录多次异常 如果我的层在单独的项目中,

我应该捕获用于日志记录的异常吗

public foo(..) { try { ... } catch (Exception ex) { Logger.Error(ex); throw; } } 公共食品(……) { 尝试 { ... }捕获(例外情况除外){ 记录器错误(ex); 投掷; } } 如果在我的每一层(DataAccess、Business和WebService)中都有这样的功能,这意味着会记录多次异常

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

绝对不行。您应该找到处理异常的正确位置(实际执行一些操作,例如catch而不是rethrow),然后记录它。当然,您可以而且应该包括整个堆栈跟踪,但是按照您的建议会在代码中添加try-catch块。

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

我的最佳做法是:

  • 仅在公共方法中使用try/catch(一般来说;显然,如果您正在捕获特定错误,您将在那里检查它)
  • 仅在抑制错误并重定向到错误页面/表单之前登录UI层

  • 使用您自己的异常来包装内置异常。通过这种方式,您可以在捕获异常时区分已知错误和未知错误。如果您有一个方法调用其他方法,这些方法可能会抛出异常以对预期和意外故障做出反应,那么这是非常有用的。如果您需要记录所有异常,那么这是一个非常好的主意。也就是说,没有其他原因记录所有异常不是一个好主意。

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


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

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

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

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


    如果您打算在再次抛出异常之前向异常添加一些有用的信息,我只会在该层处理它-将异常包装在您创建的新异常中,该异常包含除低级异常文本之外的有用信息,这通常对没有上下文的任何人都没有什么意义。

    我的方法是记录异常仅在处理程序中。可以说是“真正的”处理者。否则,日志将很难读取,并且代码的结构也会变差

    这取决于例外情况:如果这真的不应该发生,我肯定会记录它。另一方面:如果您期望出现这种异常,那么您应该考虑应用程序的设计

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

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

    最好的做法是翻译例外情况。不要只是记录它们。如果要知道引发异常的特定原因,请引发特定异常:

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

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

    通过这种方式,您可以在服务器上记录异常,而不需要在客户端机器上查找发生了什么


    我在使用远程处理或ASMXWeb服务的应用程序的业务层中使用此模式。使用WCF,您可以使用附加到ChannelDispatcher的IErrorHandler(完全是另一个主题)截获并记录异常,因此您不需要try/catch/throw模式。

    一般的经验法则是,只有在您确实可以对异常采取措施的情况下,您才能捕获异常。因此,在业务层或数据层,您只能在如下情况下捕获异常:

                try
                {
                    this.Persist(trans);
                }
                catch(Exception ex)
                {
                    trans.Rollback();
                    throw ex;
                }
    
    我的业务/数据层尝试保存数据-如果生成异常,则回滚所有事务并将异常发送到UI层

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

    Application.ThreadException+=新的ThreadExceptionEventHandler(Application\u 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),而不是抛出异常。

    您需要制定处理异常的策略。我不推荐捕猎和再捕杀。除了多余的日志条目外,它还使代码更难阅读。 考虑写入异常的构造函数中的日志。这将为要从中恢复的异常保留try/catch;使代码更易于阅读。要处理意外或不可恢复的异常,您可能需要尝试/捕获 catch (const Exception& ex) { ... }
    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
        }
    }