如何获取额外的日志记录异常详细信息? [英] How to get extra exception details for logging?

查看:177
本文介绍了如何获取额外的日志记录异常详细信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我遇到了一个问题,可以从异常获取尽可能多的细节。原因?那么当你需要解决出货产品时,日志通常是你唯一的。



显然

  Exception.ToString()

非常好,但它当您处理 FaultException 并且谁知道自定义异常给您带来什么惊喜时,并不是非常有用。



那么最好的方式是获得异常细节与偏执的偏执程度?

解决方案

我已经环顾四周了,可疑的是,没有这么多的讨论。无论如何,我试图在这里复合精髓。




  1. 这里我们有示例代码抛出异常。

      protected void TestExceptionDetails()
    {
    try
    {
    int zero = 0;

    try
    {
    int z =零/零;
    }
    catch(异常e)
    {
    var applicationException = new ApplicationException(rethrow,e);
    //放一些提示为什么异常发生
    applicationException.Data.Add(divider_value,zero);
    throw applicationException;
    }
    }
    catch(异常e)
    {
    var extendedexceptionDetails = GetExtendedexceptionDetails(e);
    log.ErrorFormat(Detailed:{0},extendedexceptionDetails);
    }
    }


  2. 这是GetExtendedExceptionDetails的方法: p>

      ///< summary> 
    ///此实用程序方法可用于从异常对象检索额外的详细信息。
    ///< / summary>
    ///< param name =e>异常< / param>
    ///< param name =indent>可选参数。用于文本缩进的字符串。< / param>
    ///< returns>具有尽可能多的细节的字符串可以从异常获取。< / returns>
    public static string GetExtendedexceptionDetails(object e,string indent = null)
    {
    //我们希望在处理错误日志时处于稳健状态
    try
    {
    var sb = new StringBuilder(indent);
    //很高兴知道异常类型
    sb.AppendLine(Type:+ e.GetType()。FullName);
    //获取我们可以读取的实例级属性
    var props = e.GetType()。GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead);

    foreach(道具中的PropertyInfo p)
    {
    try
    {
    var v = p.GetValue(e,null);

    //在Fault合同的情况下,我们想知道什么Detail包含
    if(e is FaultException&& p.Name ==Detail)
    {
    sb.AppendLine(string.Format({0} {1}:,indent,p.Name));
    sb.AppendLine(GetExtendedexceptionDetails(v,+ indent)); //递归调用
    }
    //通常这是InnerException
    else if(v is Exception)
    {
    sb.AppendLine(string.Format({0} {1}:,indent,p.Name));
    sb.AppendLine(GetExtendedexceptionDetails(v as Exception,+ indent)); //递归调用
    }
    //某些其他属性
    else
    {
    sb.AppendLine(string.Format({0} {1}:'{2}',indent,p.Name,v));

    //通常这是Data属性
    if(v is IDictionary)
    {
    var d = v as IDictionary;
    sb.AppendLine(string.Format({0} {1} = {2},+ indent,count,d.Count));
    foreach(d)中的DictionaryEntry kvp
    {
    sb.AppendLine(string.Format({0} [{1}]:[{2}],+ kvp.Key,kvp.Value));
    }
    }
    }
    }
    catch(异常异常)
    {
    // swallow or log
    }
    }

    //删除缓冲区结尾处的冗余CR + LF
    sb.Length = sb.Length - 2;
    return sb.ToString();
    }
    catch(异常异常)
    {
    // log or swallow here
    return string.Empty;
    }
    }


您可以看到我们使用Reflection来获取实例属性,然后获取它们的值。我知道这很贵,但我们并不知道具体异常暴露的可能属性。我们都希望在应用程序中经常出现这种错误并不会导致性能下降。



现在让我们来看看我们实际获得的结果。 b
$ b

这是Exception.ToString返回:

  System.ApplicationException:rethrow --- > System.DivideByZeroException:尝试除以零。 
在NET4.TestClasses.Other.TestExceptionDetails()在c:\tmp\prj\NET4\TestClasses\Other.cs:行1116
---内部异常堆栈跟踪结束---
at NET4.TestClasses.Other.TestExceptionDetails()in c:\tmp\prj\NET4\TestClasses\Other.cs:line 1123

这返回我们的新方法:

 类型:System.ApplicationException 
消息:'rethrow'
数据:'System.Collections.ListDictionaryInternal'
count = 1
[divider_value]:[0]
InnerException
类型:System.DivideByZeroException
消息:'尝试除以零'
数据:'System.Collections.ListDictionaryInternal'
count = 0
InnerException: ''
TargetSite:'Void TestExceptionDetails()'
StackTrace:'在NET4.TestClasses.Other.TestExceptionDetails()在c:\tmp\prj\NET4\TestClasses\其他。 cs:line 1116'
帮助链接:''
源:'NET4'
TargetSite:'Void TestExceptionDetails()'
StackTrace:'在NET4.TestClasses.Other.TestExceptionDetails()在c:\tmp\ prj\NET4\TestClasses\Other.cs:line 1123'
HelpLink:''
资料来源:'NET4'

我们使用 log4net 进行日志记录并降低性能开销中有 ILog.IsErrorEnabled 属性。在调用扩展异常处理之前,我只是检查它。


Recently i've encountered a problem of getting as much details from exception as i possibly could. The reason? Well, when you need to solve problems in shipped product the log is usually the only thing you have.

Obviously

Exception.ToString()

works pretty well but it is not very helpful when you deal with FaultException and who knows what surprises can custom exceptions give you.

So what is the best way to get exception details with decent level of paranoia?

解决方案

I've looked around and googled on the topic. Susrpisingly there are not so many discussions on this. Anyway I tried to compound quintessence here.

Talk is cheap. Show me the code.

  1. Here we have the sample code throwing the exception.

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

  2. Here is the method 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;
        }
    }
    

As you can see we use Reflection to get instance properties and then get their values. I know it is expensive but we don't really know what possible properties the concrete exception exposes. And we all hope that errors won't occur so often in application that it would kill the performance.

Now let's look at what we actually gained.

This is what Exception.ToString returns:

System.ApplicationException: rethrow ---> System.DivideByZeroException: Attempted to divide by zero.
   at NET4.TestClasses.Other.TestExceptionDetails() in c:\tmp\prj\NET4\TestClasses\Other.cs:line 1116
   --- End of inner exception stack trace ---
   at NET4.TestClasses.Other.TestExceptionDetails() in c:\tmp\prj\NET4\TestClasses\Other.cs:line 1123

And this returns our new method:

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'

We use log4net for logging and to reduce the performance overhead there is ILog.IsErrorEnabled property. I just check it before calling the extended exception handling.

这篇关于如何获取额外的日志记录异常详细信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆