WHOLE 예외를 문자열로 변환
전화 Exception.ToString()
는 Exception.Message
속성을 사용하는 것보다 더 많은 정보를 제공합니다 . 그러나 이것조차도 여전히 다음을 포함한 많은 정보를 남깁니다.
Data
컬렉션 속성은 모든 예외를 발견했다.
- 다른 사용자 정의 특성이 예외에 추가되었습니다.
이 추가 정보를 캡처하려는 경우가 있습니다. 아래 코드는 위의 시나리오를 처리합니다. 또한 예외의 속성을 좋은 순서로 작성합니다. C # 7을 사용하고 있지만 필요한 경우 이전 버전으로 쉽게 변환 할 수 있어야합니다. 이 관련 답변을 참조하십시오 .
public static class ExceptionExtensions
{
public static string ToDetailedString(this Exception exception) =>
ToDetailedString(exception, ExceptionOptions.Default);
public static string ToDetailedString(this Exception exception, ExceptionOptions options)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
var stringBuilder = new StringBuilder();
AppendValue(stringBuilder, "Type", exception.GetType().FullName, options);
foreach (PropertyInfo property in exception
.GetType()
.GetProperties()
.OrderByDescending(x => string.Equals(x.Name, nameof(exception.Message), StringComparison.Ordinal))
.ThenByDescending(x => string.Equals(x.Name, nameof(exception.Source), StringComparison.Ordinal))
.ThenBy(x => string.Equals(x.Name, nameof(exception.InnerException), StringComparison.Ordinal))
.ThenBy(x => string.Equals(x.Name, nameof(AggregateException.InnerExceptions), StringComparison.Ordinal)))
{
var value = property.GetValue(exception, null);
if (value == null && options.OmitNullProperties)
{
if (options.OmitNullProperties)
{
continue;
}
else
{
value = string.Empty;
}
}
AppendValue(stringBuilder, property.Name, value, options);
}
return stringBuilder.ToString().TrimEnd('\r', '\n');
}
private static void AppendCollection(
StringBuilder stringBuilder,
string propertyName,
IEnumerable collection,
ExceptionOptions options)
{
stringBuilder.AppendLine($"{options.Indent}{propertyName} =");
var innerOptions = new ExceptionOptions(options, options.CurrentIndentLevel + 1);
var i = 0;
foreach (var item in collection)
{
var innerPropertyName = $"[{i}]";
if (item is Exception)
{
var innerException = (Exception)item;
AppendException(
stringBuilder,
innerPropertyName,
innerException,
innerOptions);
}
else
{
AppendValue(
stringBuilder,
innerPropertyName,
item,
innerOptions);
}
++i;
}
}
private static void AppendException(
StringBuilder stringBuilder,
string propertyName,
Exception exception,
ExceptionOptions options)
{
var innerExceptionString = ToDetailedString(
exception,
new ExceptionOptions(options, options.CurrentIndentLevel + 1));
stringBuilder.AppendLine($"{options.Indent}{propertyName} =");
stringBuilder.AppendLine(innerExceptionString);
}
private static string IndentString(string value, ExceptionOptions options)
{
return value.Replace(Environment.NewLine, Environment.NewLine + options.Indent);
}
private static void AppendValue(
StringBuilder stringBuilder,
string propertyName,
object value,
ExceptionOptions options)
{
if (value is DictionaryEntry)
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)value;
stringBuilder.AppendLine($"{options.Indent}{propertyName} = {dictionaryEntry.Key} : {dictionaryEntry.Value}");
}
else if (value is Exception)
{
var innerException = (Exception)value;
AppendException(
stringBuilder,
propertyName,
innerException,
options);
}
else if (value is IEnumerable && !(value is string))
{
var collection = (IEnumerable)value;
if (collection.GetEnumerator().MoveNext())
{
AppendCollection(
stringBuilder,
propertyName,
collection,
options);
}
}
else
{
stringBuilder.AppendLine($"{options.Indent}{propertyName} = {value}");
}
}
}
public struct ExceptionOptions
{
public static readonly ExceptionOptions Default = new ExceptionOptions()
{
CurrentIndentLevel = 0,
IndentSpaces = 4,
OmitNullProperties = true
};
internal ExceptionOptions(ExceptionOptions options, int currentIndent)
{
this.CurrentIndentLevel = currentIndent;
this.IndentSpaces = options.IndentSpaces;
this.OmitNullProperties = options.OmitNullProperties;
}
internal string Indent { get { return new string(' ', this.IndentSpaces * this.CurrentIndentLevel); } }
internal int CurrentIndentLevel { get; set; }
public int IndentSpaces { get; set; }
public bool OmitNullProperties { get; set; }
}
맨 위 팁-로깅 예외
대부분의 사람들은이 코드를 로깅에 사용합니다. Serilog 와 함께 Serilog 를 사용하는 것을 고려하십시오. 예제 NuGet 패키지는 예외의 모든 속성을 기록하지만 대부분의 경우에 반영하지 않고 더 빠르게 수행합니다. Serilog는 작성 당시의 모든 분노 인 매우 고급 로깅 프레임 워크입니다.
맨 위 팁-사람이 읽을 수있는 스택 추적
Serilog 를 사용하는 경우 Ben.Demystifier NuGet 패키지를 사용 하여 예외에 대한 사람이 읽을 수있는 스택 추적 또는 serilog-enrichers-demystify NuGet 패키지를 얻을 수 있습니다.