Allow demystifier to add strings to existing StringBuilder (second attempt) (#80)
* Allow demystifier to add strings to existing StringBuilder * Add exception message
This commit is contained in:
parent
a9830f38e3
commit
fbd6ea49ab
@ -173,11 +173,10 @@ namespace System.Diagnostics
|
||||
// ResolveStateMachineMethod may have set declaringType to null
|
||||
if (type != null)
|
||||
{
|
||||
var declaringTypeName = TypeNameHelper.GetTypeDisplayName(type, fullName: true, includeGenericParameterNames: true);
|
||||
methodDisplayInfo.DeclaringTypeName = declaringTypeName;
|
||||
methodDisplayInfo.DeclaringType = type;
|
||||
}
|
||||
|
||||
if (method is System.Reflection.MethodInfo mi)
|
||||
if (method is MethodInfo mi)
|
||||
{
|
||||
var returnParameter = mi.ReturnParameter;
|
||||
if (returnParameter != null)
|
||||
@ -190,7 +189,6 @@ namespace System.Diagnostics
|
||||
{
|
||||
Prefix = "",
|
||||
Name = "",
|
||||
Type = TypeNameHelper.GetTypeDisplayName(mi.ReturnType, fullName: false, includeGenericParameterNames: true).ToString(),
|
||||
ResolvedType = mi.ReturnType,
|
||||
};
|
||||
}
|
||||
@ -542,7 +540,6 @@ namespace System.Diagnostics
|
||||
{
|
||||
var parameterType = parameter.ParameterType;
|
||||
var prefix = GetPrefix(parameter, parameterType);
|
||||
var parameterTypeString = "?";
|
||||
|
||||
if (parameterType == null)
|
||||
{
|
||||
@ -550,7 +547,6 @@ namespace System.Diagnostics
|
||||
{
|
||||
Prefix = prefix,
|
||||
Name = parameter.Name,
|
||||
Type = parameterTypeString,
|
||||
ResolvedType = parameterType,
|
||||
};
|
||||
}
|
||||
@ -574,40 +570,22 @@ namespace System.Diagnostics
|
||||
parameterType = parameterType.GetElementType();
|
||||
}
|
||||
|
||||
parameterTypeString = TypeNameHelper.GetTypeDisplayName(parameterType, fullName: false, includeGenericParameterNames: true);
|
||||
|
||||
return new ResolvedParameter
|
||||
{
|
||||
Prefix = prefix,
|
||||
Name = parameter.Name,
|
||||
Type = parameterTypeString,
|
||||
ResolvedType = parameterType,
|
||||
};
|
||||
}
|
||||
|
||||
private static ResolvedParameter GetValueTupleParameter(IList<string> tupleNames, string prefix, string name, Type parameterType)
|
||||
{
|
||||
string typeName;
|
||||
|
||||
if (parameterType.IsValueTuple())
|
||||
{
|
||||
typeName = GetValueTupleParameterName(tupleNames, parameterType);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to unwrap the first generic argument first.
|
||||
var genericTypeName = TypeNameHelper.GetTypeNameForGenericType(parameterType);
|
||||
var valueTupleFullName = GetValueTupleParameterName(tupleNames, parameterType.GetGenericArguments()[0]);
|
||||
typeName = $"{genericTypeName}<{valueTupleFullName}>";
|
||||
}
|
||||
|
||||
return new ResolvedParameter
|
||||
return new ValueTupleResolvedParameter
|
||||
{
|
||||
TupleNames = tupleNames,
|
||||
Prefix = prefix,
|
||||
Name = name,
|
||||
Type = typeName,
|
||||
ResolvedType = parameterType,
|
||||
ResolvedType = parameterType
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic.Enumerable;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
@ -12,27 +13,16 @@ namespace System.Diagnostics
|
||||
{
|
||||
private static readonly FieldInfo stackTraceString = typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
public static T Demystify<T>(this T exception) where T : Exception
|
||||
=> Demystify(exception, originalStacksTracker: null);
|
||||
|
||||
private static string GetStackTracesString(this Exception exception)
|
||||
=> (string)stackTraceString.GetValue(exception);
|
||||
|
||||
private static void SetStackTracesString(this Exception exception, string value)
|
||||
=> stackTraceString.SetValue(exception, value);
|
||||
|
||||
/// <summary>
|
||||
/// Demystifies the given <paramref name="exception"/> and tracks the original stack traces for the whole exception tree.
|
||||
/// </summary>
|
||||
private static T Demystify<T>(this T exception, Dictionary<Exception, string> originalStacksTracker) where T : Exception
|
||||
public static T Demystify<T>(this T exception) where T : Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
if (originalStacksTracker?.ContainsKey(exception) == false)
|
||||
{
|
||||
originalStacksTracker[exception] = exception.GetStackTracesString();
|
||||
}
|
||||
|
||||
var stackTrace = new EnhancedStackTrace(exception);
|
||||
|
||||
if (stackTrace.FrameCount > 0)
|
||||
@ -44,11 +34,11 @@ namespace System.Diagnostics
|
||||
{
|
||||
foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
|
||||
{
|
||||
ex.Demystify(originalStacksTracker);
|
||||
ex.Demystify();
|
||||
}
|
||||
}
|
||||
|
||||
exception.InnerException?.Demystify(originalStacksTracker);
|
||||
exception.InnerException?.Demystify();
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -68,28 +58,7 @@ namespace System.Diagnostics
|
||||
/// computes a demystified string representation and then restores the original state of the exception back.
|
||||
/// </remarks>
|
||||
[Contracts.Pure]
|
||||
public static string ToStringDemystified(this Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
var originalStacks = new Dictionary<Exception, string>();
|
||||
exception.Demystify(originalStacks);
|
||||
|
||||
var result = exception.ToString();
|
||||
|
||||
foreach (var kvp in originalStacks)
|
||||
{
|
||||
kvp.Key.SetStackTracesString(kvp.Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Processing exceptions shouldn't throw exceptions; if it fails
|
||||
}
|
||||
|
||||
return exception.ToString();
|
||||
}
|
||||
public static string ToStringDemystified(this Exception exception)
|
||||
=> new StringBuilder().AppendDemystified(exception).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ namespace System.Diagnostics
|
||||
{
|
||||
public MethodBase MethodBase { get; set; }
|
||||
|
||||
public string DeclaringTypeName { get; set; }
|
||||
|
||||
public Type DeclaringType { get; set; }
|
||||
|
||||
public bool IsAsync { get; set; }
|
||||
|
||||
public bool IsLambda { get; set; }
|
||||
@ -39,11 +39,9 @@ namespace System.Diagnostics
|
||||
|
||||
internal StringBuilder Append(StringBuilder builder)
|
||||
{
|
||||
|
||||
if (IsAsync)
|
||||
{
|
||||
builder
|
||||
.Append("async ");
|
||||
builder.Append("async ");
|
||||
}
|
||||
|
||||
if (ReturnParameter != null)
|
||||
@ -52,7 +50,7 @@ namespace System.Diagnostics
|
||||
builder.Append(" ");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(DeclaringTypeName))
|
||||
if (DeclaringType != null)
|
||||
{
|
||||
|
||||
if (Name == ".ctor")
|
||||
@ -60,17 +58,16 @@ namespace System.Diagnostics
|
||||
if (string.IsNullOrEmpty(SubMethod) && !IsLambda)
|
||||
builder.Append("new ");
|
||||
|
||||
builder.Append(DeclaringTypeName);
|
||||
AppendDeclaringTypeName(builder);
|
||||
}
|
||||
else if (Name == ".cctor")
|
||||
{
|
||||
builder.Append("static ");
|
||||
builder.Append(DeclaringTypeName);
|
||||
AppendDeclaringTypeName(builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder
|
||||
.Append(DeclaringTypeName)
|
||||
AppendDeclaringTypeName(builder)
|
||||
.Append(".")
|
||||
.Append(Name);
|
||||
}
|
||||
@ -145,5 +142,10 @@ namespace System.Diagnostics
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private StringBuilder AppendDeclaringTypeName(StringBuilder builder)
|
||||
{
|
||||
return DeclaringType != null ? builder.AppendTypeDisplayName(DeclaringType, fullName: true, includeGenericParameterNames: true) : builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,8 +9,6 @@ namespace System.Diagnostics
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public Type ResolvedType { get; set; }
|
||||
|
||||
public string Prefix { get; set; }
|
||||
@ -25,7 +23,15 @@ namespace System.Diagnostics
|
||||
.Append(" ");
|
||||
}
|
||||
|
||||
sb.Append(Type);
|
||||
if (ResolvedType != null)
|
||||
{
|
||||
AppendTypeName(sb);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append("?");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
sb.Append(" ")
|
||||
@ -34,5 +40,10 @@ namespace System.Diagnostics
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
protected virtual void AppendTypeName(StringBuilder sb)
|
||||
{
|
||||
sb.AppendTypeDisplayName(ResolvedType, fullName: false, includeGenericParameterNames: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
56
src/Ben.Demystifier/StringBuilderExtentions.cs
Normal file
56
src/Ben.Demystifier/StringBuilderExtentions.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) Ben A Adams. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic.Enumerable;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
public static class StringBuilderExtentions
|
||||
{
|
||||
public static StringBuilder AppendDemystified(this StringBuilder builder, Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stackTrace = new EnhancedStackTrace(exception);
|
||||
|
||||
builder.Append(exception.GetType());
|
||||
if (!string.IsNullOrEmpty(exception.Message))
|
||||
{
|
||||
builder.Append(": ").Append(exception.Message);
|
||||
}
|
||||
builder.Append(Environment.NewLine);
|
||||
|
||||
if (stackTrace.FrameCount > 0)
|
||||
{
|
||||
stackTrace.Append(builder);
|
||||
}
|
||||
|
||||
if (exception is AggregateException aggEx)
|
||||
{
|
||||
foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
|
||||
{
|
||||
builder.AppendInnerException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
builder.AppendInnerException(exception.InnerException);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Processing exceptions shouldn't throw exceptions; if it fails
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static void AppendInnerException(this StringBuilder builder, Exception exception)
|
||||
=> builder.Append(" ---> ")
|
||||
.AppendDemystified(exception)
|
||||
.AppendLine()
|
||||
.Append(" --- End of inner exception stack trace ---");
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@ using System.Text;
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
// Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.TypeNameHelper.Sources/TypeNameHelper.cs
|
||||
public class TypeNameHelper
|
||||
public static class TypeNameHelper
|
||||
{
|
||||
public static readonly Dictionary<Type, string> BuiltInTypeNames = new Dictionary<Type, string>
|
||||
{
|
||||
@ -43,6 +43,12 @@ namespace System.Diagnostics
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static StringBuilder AppendTypeDisplayName(this StringBuilder builder, Type type, bool fullName = true, bool includeGenericParameterNames = false)
|
||||
{
|
||||
ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a name of given generic type without '`'.
|
||||
/// </summary>
|
||||
|
||||
62
src/Ben.Demystifier/ValueTupleResolvedParameter.cs
Normal file
62
src/Ben.Demystifier/ValueTupleResolvedParameter.cs
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (c) Ben A Adams. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Internal;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
public class ValueTupleResolvedParameter : ResolvedParameter
|
||||
{
|
||||
public IList<string> TupleNames { get; set; }
|
||||
|
||||
protected override void AppendTypeName(StringBuilder sb)
|
||||
{
|
||||
if (ResolvedType.IsValueTuple())
|
||||
{
|
||||
AppendValueTupleParameterName(sb, ResolvedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to unwrap the first generic argument first.
|
||||
sb.Append(TypeNameHelper.GetTypeNameForGenericType(ResolvedType));
|
||||
sb.Append("<");
|
||||
AppendValueTupleParameterName(sb, ResolvedType.GetGenericArguments()[0]);
|
||||
sb.Append(">");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void AppendValueTupleParameterName(StringBuilder sb, Type parameterType)
|
||||
{
|
||||
sb.Append("(");
|
||||
var args = parameterType.GetGenericArguments();
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.AppendTypeDisplayName(args[i], fullName: false, includeGenericParameterNames: true);
|
||||
|
||||
if (i >= TupleNames.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var argName = TupleNames[i];
|
||||
if (argName == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.Append(" ");
|
||||
sb.Append(argName);
|
||||
}
|
||||
|
||||
sb.Append(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user