Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.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
.net 如何获取日志记录的额外异常详细信息?_.net_Logging_Exception Handling - Fatal编程技术网

.net 如何获取日志记录的额外异常详细信息?

.net 如何获取日志记录的额外异常详细信息?,.net,logging,exception-handling,.net,Logging,Exception Handling,最近,我遇到了一个问题,就是如何尽可能多地从exception获取详细信息。原因是什么?嗯,当您需要解决已装运产品中的问题时,日志通常是您唯一拥有的 显然 Exception.ToString() 工作得很好,但在处理FaultException时,它并没有多大帮助,谁知道自定义异常会给您带来什么惊喜 那么,用适当的偏执程度来获取异常详细信息的最佳方法是什么呢?我已经环顾四周,在谷歌上搜索了这个话题。令人欣慰的是,关于这一点的讨论并不多。无论如何,我试着在这里合成精髓 这里是引发异常的示例代

最近,我遇到了一个问题,就是如何尽可能多地从exception获取详细信息。原因是什么?嗯,当您需要解决已装运产品中的问题时,日志通常是您唯一拥有的

显然

Exception.ToString()

工作得很好,但在处理FaultException时,它并没有多大帮助,谁知道自定义异常会给您带来什么惊喜


那么,用适当的偏执程度来获取异常详细信息的最佳方法是什么呢?

我已经环顾四周,在谷歌上搜索了这个话题。令人欣慰的是,关于这一点的讨论并不多。无论如何,我试着在这里合成精髓

  • 这里是引发异常的示例代码

    protected void TestExceptionDetails()
    {
        try
        {
            int zero = 0;
    
            try
            {
                int z = zero / zero;
            }
            catch (Exception e)
            {
                var applicationException = new ApplicationException("rethrow", e);
                // put some hint why exception occured
                applicationException.Data.Add("divider_value", zero);
                throw applicationException;
            }
        }
        catch (Exception e)
        {
            var extendedexceptionDetails = GetExtendedexceptionDetails(e);
            log.ErrorFormat("Detailed:{0}", extendedexceptionDetails);
        }
    }
    
  • 以下是GetExtendedExceptionDetails方法:

    /// <summary>
    /// This utility method can be used for retrieving extra details from exception objects.
    /// </summary>
    /// <param name="e">Exception.</param>
    /// <param name="indent">Optional parameter. String used for text indent.</param>
    /// <returns>String with as much details was possible to get from exception.</returns>
    public static string GetExtendedexceptionDetails(object e, string indent = null)
    {
        // we want to be robust when dealing with errors logging
        try
        {
            var sb = new StringBuilder(indent);
            // it's good to know the type of exception
            sb.AppendLine("Type: " + e.GetType().FullName);
            // fetch instance level properties that we can read
            var props = e.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead);
    
            foreach (PropertyInfo p in props)
            {
                try
                {
                    var v = p.GetValue(e, null);
    
                    // in case of Fault contracts we'd like to know what Detail contains
                    if (e is FaultException && p.Name == "Detail")
                    {
                        sb.AppendLine(string.Format("{0}{1}:", indent, p.Name));
                        sb.AppendLine(GetExtendedexceptionDetails(v, "  " + indent));// recursive call
                    }
                    // Usually this is InnerException
                    else if (v is Exception)
                    {
                        sb.AppendLine(string.Format("{0}{1}:", indent, p.Name));
                        sb.AppendLine(GetExtendedexceptionDetails(v as Exception, "  " + indent));// recursive call
                    }
                    // some other property
                    else
                    {
                        sb.AppendLine(string.Format("{0}{1}: '{2}'", indent, p.Name, v));
    
                        // Usually this is Data property
                        if (v is IDictionary)
                        {
                            var d = v as IDictionary;
                            sb.AppendLine(string.Format("{0}{1}={2}", " " + indent, "count", d.Count));
                            foreach (DictionaryEntry kvp in d)
                            {
                                sb.AppendLine(string.Format("{0}[{1}]:[{2}]", " " + indent, kvp.Key, kvp.Value));
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    //swallow or log
                }
            }
    
            //remove redundant CR+LF in the end of buffer
            sb.Length = sb.Length - 2;
            return sb.ToString();
        }
        catch (Exception exception)
        {
            //log or swallow here
            return string.Empty;
        }
    }
    
    这将返回我们的新方法:

    Type: System.ApplicationException
    Message: 'rethrow'
    Data: 'System.Collections.ListDictionaryInternal'
     count=1
     [divider_value]:[0]
    InnerException:
      Type: System.DivideByZeroException
      Message: 'Attempted to divide by zero.'
      Data: 'System.Collections.ListDictionaryInternal'
       count=0
      InnerException: ''
      TargetSite: 'Void TestExceptionDetails()'
      StackTrace: '   at NET4.TestClasses.Other.TestExceptionDetails() in c:\tmp\prj\NET4\TestClasses\Other.cs:line 1116'
      HelpLink: ''
      Source: 'NET4'
    TargetSite: 'Void TestExceptionDetails()'
    StackTrace: '   at NET4.TestClasses.Other.TestExceptionDetails() in c:\tmp\prj\NET4\TestClasses\Other.cs:line 1123'
    HelpLink: ''
    Source: 'NET4'
    

    我们使用它来记录日志并减少性能开销。在调用扩展异常处理之前,我只需检查它。

    从异常记录信息可能很有用,但事务性日志记录方法可能提供更多信息

    其思想是尽可能多地跟踪日志消息,但不要将它们写在日志文件中,而是将它们累积到内存队列中。如果用户提交的操作已成功完成,则只需处理跟踪消息集合。但是,如果抛出异常,您可以记录异常和执行期间累积的跟踪消息


    好处是显而易见的——您不仅可以获得某些错误的信息,还可以知道系统中发生了哪些导致异常的过程。

    这是您建议的侵入性功能。它需要在代码中的许多地方进行更改,或者使用一些AOP方法。在我们公司,这种变化是多年的事。另外,在非常困难的情况下,我们总是可以得到进程的内存转储,我们将确切地知道发生了什么。我相信log4net现在是一个事实上的工业标准。我甚至在银行应用程序中也见过它。“谁知道自定义异常会给你带来什么惊喜”+1!如果有人需要进一步澄清:自定义异常类可能会重写ToString()并返回“Hello,world!”或其他任何消息。
    protected void TestExceptionDetails()
    {
        try
        {
            int zero = 0;
    
            try
            {
                int z = zero / zero;
            }
            catch (Exception e)
            {
                var applicationException = new ApplicationException("rethrow", e);
                // put some hint why exception occured
                applicationException.Data.Add("divider_value", zero);
                throw applicationException;
            }
        }
        catch (Exception e)
        {
            var extendedexceptionDetails = GetExtendedexceptionDetails(e);
            log.ErrorFormat("Detailed:{0}", extendedexceptionDetails);
        }
    }