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