Add ToString to StackFrame and DeminifyStackTraceResult to make printing a deminified stack trace easy (#71)

This commit is contained in:
Ian Craig 2019-08-12 11:01:34 -07:00 коммит произвёл Christian Gonzalez
Родитель 83a140d1d7
Коммит c2d4546b69
7 изменённых файлов: 108 добавлений и 4 удалений

Просмотреть файл

@ -144,7 +144,8 @@ The top level API for call stack deminification is the `StackTraceDeminifier.Dem
```csharp
StackTraceDeminifier sourceMapCallstackDeminifier = StackTraceDeminfierFactory.GetStackTraceDeminfier(new SourceMapProvider(), new SourceCodeProvider());
DeminifyStackTraceResult deminifyStackTraceResult = sourceMapCallstackDeminifier.DeminifyStackTrace(callstack)
DeminifyStackTraceResult deminifyStackTraceResult = sourceMapCallstackDeminifier.DeminifyStackTrace(callstack);
string deminifiedCallstack = deminifyStackTraceResult.ToString();
```
The result of `DeminifyStackTrace` is a `DeminifyStackTraceResult`, which is an object that contains a list of `StackFrameDeminificationResults` which contains the parsed minified `StackFrame` objects in the `MinifiedStackFrame` property and an enum indicating if any errors occured when attempting to deminify the `StackFrame`. The `DeminifiedStackFrame` property contains the best guess `StackFrame` object that maps to the `MinifiedStackFrame` element with the same index. Note that any of the properties on a `StackTrace` object may be null if no value could be extracted from the input callstack string or source map.

Просмотреть файл

@ -1,11 +1,28 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace SourcemapToolkit.CallstackDeminifier
{
public class DeminifyStackTraceResult
{
public string Message;
public List<StackFrame> MinifiedStackFrames;
public List<StackFrameDeminificationResult> DeminifiedStackFrameResults;
public override string ToString()
{
string output = Message ?? string.Empty;
for (int i = 0; i < DeminifiedStackFrameResults.Count; i++)
{
StackFrame deminFrame = DeminifiedStackFrameResults[i].DeminifiedStackFrame;
StackFrame frame = string.IsNullOrEmpty(deminFrame.MethodName) ? MinifiedStackFrames[i] : deminFrame;
output += $"{Environment.NewLine} {frame}";
}
return output;
}
}
}

Просмотреть файл

@ -15,6 +15,22 @@ namespace SourcemapToolkit.CallstackDeminifier
/// Any parts of the stack trace that could not be parsed are excluded from
/// the result. Does not ever return null.
/// </returns>
/// <remarks>
/// This override drops the Message out param for backward compatibility
/// </remarks>
List<StackFrame> ParseStackTrace(string stackTraceString);
/// <summary>
/// Generates a list of StackFrame objects based on the input stack trace.
/// This method normalizes differences between different browsers.
/// The source positions in the parsed stack frames will be normalized so they
/// are zero-based instead of one-based to align with the rest of the library.
/// </summary>
/// <returns>
/// Returns a list of StackFrame objects corresponding to the stackTraceString.
/// Any parts of the stack trace that could not be parsed are excluded from
/// the result. Does not ever return null.
/// </returns>
List<StackFrame> ParseStackTrace(string stackTraceString, out string message);
}
}

Просмотреть файл

@ -21,5 +21,19 @@ namespace SourcemapToolkit.CallstackDeminifier
/// The zero-based position of this stack entry.
/// </summary>
public SourcePosition SourcePosition { get; set; }
public override string ToString()
{
string output = $"at {(string.IsNullOrWhiteSpace(MethodName) ? "?" : MethodName)}";
if (!string.IsNullOrWhiteSpace(FilePath))
{
output += $" in {FilePath}";
if (SourcePosition != null)
{
output += $":{SourcePosition.ZeroBasedLineNumber}:{SourcePosition.ZeroBasedColumnNumber}";
}
}
return output;
}
}
}

Просмотреть файл

@ -24,7 +24,8 @@ namespace SourcemapToolkit.CallstackDeminifier
public DeminifyStackTraceResult DeminifyStackTrace(string stackTraceString)
{
DeminifyStackTraceResult result = new DeminifyStackTraceResult();
result.MinifiedStackFrames = _stackTraceParser.ParseStackTrace(stackTraceString);
result.MinifiedStackFrames = _stackTraceParser.ParseStackTrace(stackTraceString, out string message);
result.Message = message;
result.DeminifiedStackFrameResults = new List<StackFrameDeminificationResult>();
foreach (StackFrame minifiedStackFrame in result.MinifiedStackFrames)

Просмотреть файл

@ -26,16 +26,43 @@ namespace SourcemapToolkit.CallstackDeminifier
/// Any parts of the stack trace that could not be parsed are excluded from
/// the result. Does not ever return null.
/// </returns>
/// <remarks>
/// This override drops the Message out param for backward compatibility
/// </remarks>
public List<StackFrame> ParseStackTrace(string stackTraceString)
{
return ParseStackTrace(stackTraceString, out string message);
}
/// <summary>
/// Generates a list of StackFrame objects based on the input stack trace.
/// This method normalizes differences between different browsers.
/// The source positions in the parsed stack frames will be normalized so they
/// are zero-based instead of one-based to align with the rest of the library.
/// </summary>
/// <returns>
/// Returns a list of StackFrame objects corresponding to the stackTraceString.
/// Any parts of the stack trace that could not be parsed are excluded from
/// the result. Does not ever return null.
/// </returns>
public List<StackFrame> ParseStackTrace(string stackTraceString, out string message)
{
if (stackTraceString == null)
{
throw new ArgumentNullException(nameof(stackTraceString));
}
message = null;
List<StackFrame> stackTrace = new List<StackFrame>();
List<string> stackFrameStrings = stackTraceString.Split('\n').ToList();
var firstFrame = stackFrameStrings.First();
if (!firstFrame.StartsWith(" ") && TryExtractMethodNameFromFrame(firstFrame) == null)
{
message = firstFrame.Trim();
stackFrameStrings.RemoveAt(0);
}
foreach (string frame in stackFrameStrings)
{
StackFrame parsedStackFrame = TryParseSingleStackFrame(frame);

Просмотреть файл

@ -112,5 +112,33 @@ window.onload/<@http://localhost:11323/crashcauser.min.js:1:445";
// Assert
ValidateDeminifyStackTraceResults(results);
}
}
[Fact]
public void DeminifyResultToString_SuccessfullyDeminified_AllLinesDeminified()
{
// Arrange
StackTraceDeminifier stackTraceDeminifier = GetStackTraceDeminifierWithDependencies();
string ieStackTrace = @"TypeError: Unable to get property 'length' of undefined or null reference
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:112)
at i (http://localhost:11323/crashcauser.min.js:1:95)
at t (http://localhost:11323/crashcauser.min.js:1:75)
at n (http://localhost:11323/crashcauser.min.js:1:50)
at causeCrash (http://localhost:11323/crashcauser.min.js:1:341)
at Anonymous function (http://localhost:11323/crashcauser.min.js:1:445)";
DeminifyStackTraceResult results = stackTraceDeminifier.DeminifyStackTrace(ieStackTrace);
string exectedResult = @"TypeError: Unable to get property 'length' of undefined or null reference
at level3 in crashcauser.js:16:12
at level3 in crashcauser.js:14:9
at level2 in crashcauser.js:10:8
at level1 in crashcauser.js:5:8
at causeCrash in crashcauser.js:27:4
at window in crashcauser.js:32:8";
// Act
string formatted = results.ToString();
// Assert
Assert.Equal(exectedResult, formatted);
}
}
}