internal ExceptionOptions(ExceptionOptions options, int currentIndent) { this.CurrentIndentLevel = currentIndent; this.IndentSpaces = options.IndentSpaces; this.OmitNullProperties = options.OmitNullProperties; }
/// <summary> /// translate exception object to string, with additional system info /// The serializable exception object is much easier to work with, serialize, convert to string /// or retrieve specific information from. /// </summary> /// <param name="ex"></param> /// <returns></returns> public static string ToString(this Exception ex, ExceptionOptions options) { if (ex == null) { return(string.Empty); } StringBuilder sb = new StringBuilder(); try { // grab some extended information for the exception var extendedProps = new List <KeyValuePair <string, object> >(); // only need the extended properties once if (options.CurrentIndentLevel == 0) { sb.AppendLine(string.Format("{0}Exception: {1}", options.Indent, ex.GetType().FullName)); extendedProps.Add(new KeyValuePair <string, object>("Type", ex.GetType().FullName)); extendedProps.Add(new KeyValuePair <string, object>("Date and Time", DateTime.Now.ToString())); extendedProps.Add(new KeyValuePair <string, object>("Machine Name", Environment.MachineName)); extendedProps.Add(new KeyValuePair <string, object>("Current IP", Utilities.GetCurrentIP())); extendedProps.Add(new KeyValuePair <string, object>("Current User", Utilities.GetUserIdentity())); extendedProps.Add(new KeyValuePair <string, object>("Application Domain", System.AppDomain.CurrentDomain.FriendlyName)); extendedProps.Add(new KeyValuePair <string, object>("Assembly Codebase", Utilities.ParentAssembly.CodeBase)); extendedProps.Add(new KeyValuePair <string, object>("Assembly Fullname", Utilities.ParentAssembly.FullName)); extendedProps.Add(new KeyValuePair <string, object>("Assembly Version", Utilities.ParentAssembly.GetName().Version.ToString())); extendedProps.Add(new KeyValuePair <string, object>("Assembly Build Date", Utilities.GetAssemblyBuildDate(Utilities.ParentAssembly).ToString())); } // gather up all the properties of the Exception, plus the extended info above // sort it, and render to a stringbuilder foreach (KeyValuePair <string, object> item in ex .GetType() .GetProperties() .Select(x => new KeyValuePair <string, object>(x.Name, x)) .Concat(extendedProps) .OrderByDescending(x => string.Equals(x.Key, "Type", StringComparison.Ordinal)) .ThenByDescending(x => string.Equals(x.Key, nameof(ex.Message), StringComparison.Ordinal)) .ThenByDescending(x => string.Equals(x.Key, nameof(ex.Source), StringComparison.Ordinal)) .ThenBy(x => string.Equals(x.Key, nameof(ex.InnerException), StringComparison.Ordinal)) .ThenBy(x => string.Equals(x.Key, nameof(AggregateException.InnerExceptions), StringComparison.Ordinal)) .ThenBy(x => x.Key)) { object value = item.Value; if (item.Key == "StackTrace") { //handle the stacktrace special var buf = new StackTrace(ex).ToString(true).TrimEnd('\r', '\n').Replace("\r\n", string.Format("\r\n{0, -23}", "")).TrimEnd(); if (string.IsNullOrEmpty(buf) && options.OmitNullProperties) { continue; } value = buf; } else if (item.Value is PropertyInfo) { value = (item.Value as PropertyInfo).GetValue(ex, null); if (value == null || (value is string && string.IsNullOrEmpty((string)value))) { if (options.OmitNullProperties) { continue; } else { value = string.Empty; } } } sb.AppendValue(item.Key, value, options); } return(sb.ToString().TrimEnd('\r', '\n')); } catch (Exception ex2) { sb.Clear(); sb.AppendLine(string.Format("{0} Error '{1}' while generating exception description", ex2.GetType().Name, ex2.Message)); } return(sb.ToString()); }