记录所有异常信息,无论是哪种类型的异常。

6

我正在使用C#、ASP.NET MVC Web Api、Entity Framework和.NET Framework 4.0进行开发。

我有以下代码来记录异常:

public void LogCompleteException(
    string controllerName,
    string actionName,
    Exception exception)
{
    string exceptionMessage = string.Empty;

    Exception e = exception;
    if (e.InnerException == null)
        e = null;
    else
        while (e.InnerException != null) e = e.InnerException;

    if (e == null)
        exceptionMessage = exception.Message;
    else
        exceptionMessage = string.Format("{0}\n\rInnerException: {1}", exception.Message, e.Message);

    _logger.ErrorFormat(
        LogTextFormatString,
        ExceptionText,
        controllerName,
        actionName,
        exceptionMessage);
}

但是在我的日志文件中,我发现了这个:

验证失败了一个或多个实体。请查看“EntityValidationErrors”属性以获取更多详细信息。

当我写下“查看“EntityValidationErrors”属性以获取更多详细信息。”时,我只是举了一个例子,其中我没有记录一个重要属性。
有很多种异常类型;但是用我的方法,我没有记录所有相关信息,因为可能会有像“EntityValidationErrors”这样的属性我没有记录。
当我将异常传递给记录器时,我不知道它有什么属性,也不知道如何记录它每个属性。
你知道一种将异常完全记录的方法吗?我的代码没有记录带有“EntityValidationErrors”属性或任何其他重要属性的异常。
我正在使用log4net进行记录。

我假设日志记录是通过log4net完成的? - Brad C
是的,我正在使用log4net进行日志记录。 - VansFannel
为什么不使用exception.ToString()? - Giorgi Nakeuri
1
你在 Stack Overflow 上看过类似的帖子吗?可以安全地假设你不想捕获 DbEntityValidationException 异常并自己创建完整的错误消息吗? - Michael
@Michael DbEntityValidationException 异常只是一个我可以得到许多种异常而且没有任何重要信息的例子。 - VansFannel
2个回答

3

由于内部异常本身就是一个异常,因此您可以递归并重用您已经拥有的方法:

if (e.InnerException != null)
{
    LogCompleteException(controllerName, actionName, e.InnerException);
}

如果这样做起作用,但是您仍然会缺少EntityValidationErrors。

另一种方法是最近我使用的方法,就是在发生异常的地方明确地捕获和记录异常:

try
{
    db.Add(something);
    db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
    StringBuilder sb = new StringBuilder();

    // collect some extra info about the exception before logging
    foreach (var eve in ex.EntityValidationErrors)
    {
        sb.AppendLine(String.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State));
        foreach (var ve in eve.ValidationErrors)
        {
            sb.AppendLine(String.Format("Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));
        }
    }

    logger.Error("There was an error while trying to parse and save something!\n" + sb.ToString(), ex);
}

如果您想要 Exception.Data 字典条目,您也可以添加它们:
foreach (DictionaryEntry entry in ex.Data)
{
    // you will want to use a StringBuilder instead of concatenating strings if you do this
    exceptionMessage = exceptionMessage + string.Format("Exception.Data[{0}]: {1}", entry.Key, entry.Value);
}

对于自定义异常类的属性,比如实体验证错误(EntityValidationErrors),我建议只在发生错误时捕获并解析它们。否则,您将不得不在每个异常类型上重写ToString()方法或使用一些反射技巧来枚举所有属性,这将显着使日志中充斥着您不关心的属性。


我觉得我在我的问题中没有解释清楚。当我写“查看'EntityValidationErrors'属性以获取更多详细信息。”时,我展示了一个我没有记录重要属性的例子。有很多种异常情况,而我的方法并没有记录所有这些信息。 - VansFannel
你能给出更多关键属性的例子吗?绝大多数异常将这些数据存储在Exception.Data字典中。然而,有一些异常(例如EntityValidationErrrors)并不是如此,并且您需要使用反射来枚举所有异常的属性,或者事先明确检查它们。对于这些异常,最好在抛出时处理它们,根据需要进行处理,就像我示例代码中所做的那样。 - Brad C
我无法给你更多关于“导入属性”方面的例子,因为我不知道我需要记录哪种类型的异常。这就是为什么我询问如何完全记录异常,因为我想记录任何带有信息的属性。顺便说一下,我使用以下代码记录最内部的InnerExceptionwhile (e.InnerException != null) e = e.InnerException; - VansFannel

0
你可以使用elmahlog4net appender。Elmah记录所有异常并将它们记录到log4net实例中。

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