Created
December 7, 2015 00:02
-
-
Save IanYates/876eea690e4ca3e72d89 to your computer and use it in GitHub Desktop.
Serilog.Exceptions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
public class AggregateExceptionDestructurer : ExceptionDestructurer | |
{ | |
public override Type[] TargetTypes | |
{ | |
get { return new Type[] { typeof(AggregateException) }; } | |
} | |
public override void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException) | |
{ | |
base.Destructure(exception, data, destructureException); | |
var aggregateException = (AggregateException)exception; | |
data.Add( | |
nameof(AggregateException.InnerExceptions), | |
aggregateException.InnerExceptions.Select(destructureException).ToList()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
public class ArgumentExceptionDestructurer : ExceptionDestructurer | |
{ | |
public override Type[] TargetTypes | |
{ | |
get { return new Type[] { typeof(ArgumentException) }; } | |
} | |
public override void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException) | |
{ | |
base.Destructure(exception, data, destructureException); | |
var argumentException = (ArgumentException)exception; | |
data.Add(nameof(ArgumentException.ParamName), argumentException.ParamName); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
public class ExceptionDestructurer : IExceptionDestructurer | |
{ | |
public virtual Type[] TargetTypes | |
{ | |
get | |
{ | |
return new Type[] | |
{ | |
typeof(AccessViolationException), | |
typeof(AppDomainUnloadedException), | |
typeof(ApplicationException), | |
typeof(ArithmeticException), | |
typeof(ArrayTypeMismatchException), | |
// typeof(BadImageFormatException), FileName, FusionLog | |
typeof(CannotUnloadAppDomainException), | |
typeof(ContextMarshalException), | |
typeof(DataMisalignedException), | |
typeof(DivideByZeroException), | |
typeof(DllNotFoundException), | |
typeof(DuplicateWaitObjectException), | |
typeof(EntryPointNotFoundException), | |
typeof(Exception), | |
typeof(FieldAccessException), | |
typeof(FormatException), | |
typeof(IndexOutOfRangeException), | |
typeof(InsufficientExecutionStackException), | |
typeof(InsufficientMemoryException), | |
typeof(InvalidCastException), | |
typeof(InvalidOperationException), | |
typeof(InvalidProgramException), | |
typeof(InvalidTimeZoneException), | |
typeof(KeyNotFoundException), | |
typeof(MemberAccessException), | |
typeof(MissingFieldException), | |
typeof(MissingMemberException), | |
typeof(MissingMethodException), | |
typeof(MulticastNotSupportedException), | |
typeof(NotFiniteNumberException), | |
typeof(NotImplementedException), | |
typeof(NotSupportedException), | |
typeof(NullReferenceException), | |
// typeof(ObjectDisposedException), ObjectName | |
typeof(OperationCanceledException), | |
typeof(OutOfMemoryException), | |
typeof(OverflowException), | |
typeof(PlatformNotSupportedException), | |
typeof(RankException), | |
typeof(StackOverflowException), | |
typeof(SystemException), | |
typeof(TimeoutException), | |
typeof(TimeZoneNotFoundException), | |
typeof(TypeAccessException), | |
// typeof(TypeInitializationException), TypeName | |
// typeof(TypeLoadException), TypeName | |
typeof(TypeUnloadedException), | |
typeof(UnauthorizedAccessException), | |
typeof(UriFormatException) | |
}; | |
} | |
} | |
public virtual void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> innerDestructure) | |
{ | |
data.Add("Type", exception.GetType().FullName); | |
if (exception.Data.Count != 0) | |
{ | |
data.Add( | |
nameof(Exception.Data), | |
exception.Data | |
.Cast<DictionaryEntry>() | |
.Where(k => k.Key is string) | |
.ToDictionary(e => (string)e.Key, e => e.Value)); | |
} | |
if (!string.IsNullOrEmpty(exception.HelpLink)) | |
{ | |
data.Add(nameof(Exception.HelpLink), exception.HelpLink); | |
} | |
if (exception.HResult != 0) | |
{ | |
data.Add(nameof(Exception.HResult), exception.HResult); | |
} | |
data.Add(nameof(Exception.Message), exception.Message); | |
data.Add(nameof(Exception.Source), exception.Source); | |
data.Add(nameof(Exception.StackTrace), exception.StackTrace); | |
if (exception.TargetSite != null) | |
{ | |
data.Add(nameof(Exception.TargetSite), exception.TargetSite.ToString()); | |
} | |
if (exception.InnerException != null) | |
{ | |
data.Add(nameof(Exception.InnerException), innerDestructure(exception.InnerException)); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
using Serilog.Core; | |
using Serilog.Events; | |
/// <summary> | |
/// Enrich a <see cref="LogEvent"/> with details about an <see cref="LogEvent.Exception"/> if present. | |
/// https://groups.google.com/forum/#!searchin/getseq/enhance$20exception/getseq/rsAL4u3JpLM/PrszbPbtEb0J | |
/// </summary> | |
public sealed class ExceptionEnricher : ILogEventEnricher | |
{ | |
public static readonly IExceptionDestructurer[] DefaultDestructurers = | |
{ | |
new ExceptionDestructurer(), | |
new ArgumentExceptionDestructurer(), | |
new AggregateExceptionDestructurer(), | |
new ReflectionTypeLoadExceptionDestructurer(), | |
new SqlExceptionDestructurer() | |
}; | |
public static readonly IExceptionDestructurer ReflectionBasedDestructurer = new ReflectionBasedDestructurer(); | |
private readonly Dictionary<Type, IExceptionDestructurer> destructurers; | |
public ExceptionEnricher() | |
: this(DefaultDestructurers) | |
{ | |
} | |
public ExceptionEnricher(params IExceptionDestructurer[] destructurers) | |
: this((IEnumerable<IExceptionDestructurer>)destructurers) | |
{ | |
} | |
public ExceptionEnricher(IEnumerable<IExceptionDestructurer> destructurers) | |
{ | |
this.destructurers = new Dictionary<Type, IExceptionDestructurer>(); | |
foreach (var destructurer in destructurers) | |
{ | |
foreach (var targetType in destructurer.TargetTypes) | |
{ | |
this.destructurers.Add(targetType, destructurer); | |
} | |
} | |
} | |
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) | |
{ | |
if (logEvent.Exception != null) | |
{ | |
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty( | |
"ExceptionDetail", | |
this.DestructureException(logEvent.Exception), | |
true)); | |
} | |
} | |
private Dictionary<string, object> DestructureException(Exception exception) | |
{ | |
var data = new Dictionary<string, object>(); | |
var exceptionType = exception.GetType(); | |
if (this.destructurers.ContainsKey(exceptionType)) | |
{ | |
var destructurer = this.destructurers[exceptionType]; | |
destructurer.Destructure(exception, data, this.DestructureException); | |
} | |
else | |
{ | |
ReflectionBasedDestructurer.Destructure(exception, data, this.DestructureException); | |
} | |
return data; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
public interface IExceptionDestructurer | |
{ | |
Type[] TargetTypes { get; } | |
void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
public class ReflectionBasedDestructurer : IExceptionDestructurer | |
{ | |
private const int MaxRecursiveLevel = 10; | |
public Type[] TargetTypes | |
{ | |
get { return new Type[] { typeof(Exception) }; } | |
} | |
public void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException) | |
{ | |
foreach (var p in this.DestructureObject(exception, exception.GetType(), 0)) | |
{ | |
data.Add(p.Key, p.Value); | |
} | |
} | |
private object DestructureValue(object value, int level) | |
{ | |
if (value == null) | |
{ | |
return null; | |
} | |
var valueType = value.GetType(); | |
if (valueType.IsSubclassOf(typeof(MemberInfo))) | |
{ | |
return value; | |
} | |
if (Type.GetTypeCode(valueType) != TypeCode.Object || valueType.IsValueType) | |
{ | |
return value; | |
} | |
if (level >= MaxRecursiveLevel) | |
{ | |
return value; | |
} | |
if (typeof(IDictionary).IsAssignableFrom(valueType)) | |
{ | |
return ((IDictionary)value) | |
.Cast<DictionaryEntry>() | |
.Where(e => e.Key is string) | |
.ToDictionary(e => (string)e.Key, e => this.DestructureValue(e.Value, level + 1)); | |
} | |
if (typeof(IEnumerable).IsAssignableFrom(valueType)) | |
{ | |
return ((IEnumerable)value) | |
.Cast<object>() | |
.Select(o => this.DestructureValue(o, level + 1)) | |
.ToList(); | |
} | |
return this.DestructureObject(value, valueType, level); | |
} | |
private IDictionary<string, object> DestructureObject(object value, Type valueType, int level) | |
{ | |
var values = valueType | |
.GetProperties(BindingFlags.Public | BindingFlags.Instance) | |
.Where(p => p.CanRead) | |
.ToDictionary(p => p.Name, p => this.DestructureValue(p.GetValue(value), level + 1)); | |
values.Add("Type", valueType); | |
return values; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
public class ReflectionTypeLoadExceptionDestructurer : ExceptionDestructurer | |
{ | |
public override Type[] TargetTypes | |
{ | |
get { return new Type[] { typeof(ReflectionTypeLoadException) }; } | |
} | |
public override void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException) | |
{ | |
base.Destructure(exception, data, destructureException); | |
var reflectionTypeLoadException = (ReflectionTypeLoadException)exception; | |
if (reflectionTypeLoadException.LoaderExceptions != null) | |
{ | |
data.Add( | |
nameof(ReflectionTypeLoadException.LoaderExceptions), | |
reflectionTypeLoadException.LoaderExceptions.Select(destructureException).ToList()); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Serilog.Exceptions | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Data.SqlClient; | |
using System.Linq; | |
public class SqlExceptionDestructurer : ExceptionDestructurer | |
{ | |
public override Type[] TargetTypes | |
{ | |
get { return new Type[] { typeof(SqlException) }; } | |
} | |
public override void Destructure( | |
Exception exception, | |
IDictionary<string, object> data, | |
Func<Exception, IDictionary<string, object>> destructureException) | |
{ | |
base.Destructure(exception, data, destructureException); | |
var sqlException = (SqlException)exception; | |
data.Add(nameof(SqlException.ClientConnectionId), sqlException.ClientConnectionId); | |
data.Add(nameof(SqlException.Class), sqlException.Class); | |
data.Add(nameof(SqlException.LineNumber), sqlException.LineNumber); | |
data.Add(nameof(SqlException.Number), sqlException.Number); | |
data.Add(nameof(SqlException.Server), sqlException.Server); | |
data.Add(nameof(SqlException.State), sqlException.State); | |
data.Add(nameof(SqlException.Errors), sqlException.Errors.Cast<SqlError>().ToList()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment