【问题标题】:How do you add context to exceptions without tons of boilerplate code?如何在没有大量样板代码的情况下为异常添加上下文?
【发布时间】:2009-03-23 14:02:54
【问题描述】:

在我目前的项目中,我看到很多这种类型的代码:

public User GetUserByName(string userName) 
{
    try
    {
        // Lots of code here to check if the user is in the cache,
        // get it from the DB if not, set properties on it, etc...
    }
    catch (Exception ex)
    {
        throw new Exception("Exception getting user by name, username: " + userName, ex);
    }
}

我很欣赏这里的意图,使用局部变量对于调试确实很有用,但是在 every 方法周围放置一个 try/catch 似乎工作量太大,而且确实无济于事可读性。现在我忽略了我们正在抛出 System.Exception 的事实,自然更具体的类型会更好,但这不是我问题的重点。不用说,这可能会被大量复制和粘贴,而对异常消息没有任何修改...

所以我的问题是:如何捕获这种上下文信息(例如上面示例中的用户名)以进行调试?出于问题的目的,我们假设该方法编写得很好,并且任何特定异常检查都得到了处理,我想要的只是为任何无法处理的异常添加上下文在这里,需要冒泡到顶级处理程序。

我的第一个想法:

  1. 依靠日志记录框架来跟踪每个方法调用及其参数,这又是真正的样板文件,而且日志记录远远超过生产环境。

  2. 引入一些 AOP 并拦截每个方法(或有限的子集),在返回时检查异常并记录参数或将它们添加到抛出的异常中。

欢迎提出其他意见!

【问题讨论】:

    标签: .net exception-handling


    【解决方案1】:

    我添加了一条带有方法名称的日志消息,然后重新抛出异常。异常只应在不可预见的情况下发生,因此供程序员使用来修复。对于程序员来说最重要的是知道异常发生在哪里以及日志消息的作用(如果它是通用方法名,我也会将类名添加到日志消息中)。

    public User GetUserByName(string userName) 
    {    
        try    
        {        
    
        }    
        catch (Exception ex)   
        {        
           logger.Error("Exception GetUserByName. " + ex.Message);
           throw;
        }
    }
    

    【讨论】:

    • 可以抛出异常,这并不意味着您必须修复代码中的某些内容。例如数据库连接可能会丢失。
    • 如果您预计会发生异常,例如数据库连接丢失,那么您可以适当地处理它。如果你遇到了一个你没有经历过的异常,那么你确实需要修复它。
    • @sipwiz - 这比重新抛出要好得多,但是,您不觉得将所有方法包装在 try/catch 块中是重复的吗?
    • 我不会将所有方法都包装在 try/catch 块中,只有那些我判断有可能发生意外异常的方法。我将始终在“主要”级别捕获异常,以便应用程序不会崩溃,但为了追踪异常,了解该方法是一个很大的开端。
    【解决方案2】:

    抛出异常是代码的正常行为。没有理由去挖掘日志来找出这样做的原因或是谁。并更改您的代码以使这种情况不再发生。

    抛出异常意味着出现问题。但不是用代码。这可能是数据库连接、用户输入、其他环境的问题。

    您可以为日志捕获的唯一异常是逻辑异常。找出程序员在哪里出错。只有这个异常你必须修复和记录。所有其他异常都应该在适当的抽象级别被捕获,而无需重新抛出。

    【讨论】:

      【解决方案3】:

      您的 Try-Catch 块应该只包含能够引发异常的代码片段(任何涉及用户输入的代码,任何涉及外部数据源的代码) 在这些情况下,最好只记录相关的局部变量。这些异常是预期的(不可避免的),因此您需要以区分预期错误和代码错误的方式记录它们。

      如果您没有在消息中添加额外的上下文,那么您就是在滥用您的日志工具。捕获和重新抛出总比完全不捕获要好(它执行 finally 块),但您还应该在每条日志消息中添加相关注释,否则您实际上会损害您调试代码的能力,因为您有不知道异常是从哪里引发的。

      此外,.Log 文件很便宜,每当您抛出错误时,在其中包含大量信息并没有什么坏处。您拥有的错误日志记录越多,调试生产应用程序就越容易。

      【讨论】:

        猜你喜欢
        • 2018-10-28
        • 2013-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-26
        相关资源
        最近更新 更多