Created
December 4, 2019 23:38
-
-
Save bsutton/75c3335f39438b4a24b96b0d9b2a5398 to your computer and use it in GitHub Desktop.
StackTraceImpl
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
import "dart:core" as core show StackTrace; | |
import "dart:core"; | |
import 'dart:io'; | |
import 'package:path/path.dart'; | |
class StackTraceImpl implements core.StackTrace { | |
static final stackTraceRegex = RegExp(r'#[0-9]+[\s]+(.+) \(([^\s]+)\)'); | |
final core.StackTrace stackTrace; | |
final String workingDirectory; | |
int _skipFrames; | |
List<Stackframe> _frames; | |
/// You can suppress call frames from showing | |
/// by specifing a non-zero value for [skipFrames] | |
/// If the workingDirectory is provided we will output | |
/// a full file path to the dart library. | |
StackTraceImpl({int skipFrames = 0, this.workingDirectory}) | |
: stackTrace = core.StackTrace.current, | |
_skipFrames = skipFrames + 1; // always skip ourselves. | |
/// | |
/// Returns a File instance for the current stackframe | |
/// | |
File get sourceFile { | |
return frames[0].sourceFile; | |
} | |
/// | |
/// Returns the Filename for the current stackframe | |
/// | |
String get sourceFilename => basename(sourcePath); | |
/// | |
/// returns the full path for the current stackframe file | |
/// | |
String get sourcePath => sourceFile.path; | |
/// | |
/// Returns the filename for the current stackframe | |
/// | |
int get lineNo { | |
return frames[0].lineNo; | |
} | |
/// Outputs a formatted string of the current stack_trace_nj | |
/// showing upto [methodCount] methods in the trace. | |
/// [methodCount] defaults to 10. | |
String formatStackTrace( | |
{bool showPath = false, int methodCount = 10, int skipFrames = 0}) { | |
var formatted = <String>[]; | |
var count = 0; | |
for (Stackframe stackFrame in frames) { | |
if (skipFrames > 0) { | |
skipFrames--; | |
continue; | |
} | |
String sourceFile; | |
if (showPath) { | |
sourceFile = stackFrame.sourceFile.path; | |
} else { | |
sourceFile = basename(stackFrame.sourceFile.path); | |
} | |
var newLine = | |
("${sourceFile} : ${stackFrame.details} : ${stackFrame.lineNo}"); | |
if (workingDirectory != null) { | |
formatted.add("file:///" + workingDirectory + newLine); | |
} else { | |
formatted.add(newLine); | |
} | |
if (++count == methodCount) { | |
break; | |
} | |
} | |
if (formatted.isEmpty) { | |
return null; | |
} else { | |
return formatted.join('\n'); | |
} | |
} | |
List<Stackframe> get frames { | |
if (_frames == null) { | |
_frames = _extractFrames(); | |
} | |
return _frames; | |
} | |
String toString() { | |
return formatStackTrace(); | |
} | |
List<Stackframe> _extractFrames() { | |
var lines = stackTrace.toString().split("\n"); | |
// we don't want the call to StackTrace to be on the stack. | |
int skipFrames = _skipFrames; | |
var stackFrames = <Stackframe>[]; | |
for (var line in lines) { | |
if (skipFrames > 0) { | |
skipFrames--; | |
continue; | |
} | |
var match = stackTraceRegex.matchAsPrefix(line); | |
if (match == null) continue; | |
// source is one of two formats | |
String source = match.group(2); | |
List<String> sourceParts = source.split(":"); | |
ArgumentError.value(sourceParts.length == 4, | |
"Stackframe source does not contain the expeted no of colons '$source'"); | |
String column = "0"; | |
String lineNo = "0"; | |
String sourcePath = sourceParts[1]; | |
if (sourceParts.length > 2) { | |
lineNo = sourceParts[2]; | |
} | |
if (sourceParts.length > 3) { | |
column = sourceParts[3]; | |
} | |
// the actual contents of the line (sort of) | |
String details = match.group(1); | |
sourcePath = sourcePath.replaceAll('<anonymous closure>', '()'); | |
sourcePath = sourcePath.replaceAll("package:", ""); | |
Stackframe frame = Stackframe( | |
File(sourcePath), int.parse(lineNo), int.parse(column), details); | |
stackFrames.add(frame); | |
} | |
return stackFrames; | |
} | |
} | |
/// | |
/// A single frame from a stack trace. | |
/// Holds the sourceFile name and line no. | |
/// | |
class Stackframe { | |
final File sourceFile; | |
final int lineNo; | |
final int column; | |
final String details; | |
Stackframe(this.sourceFile, this.lineNo, this.column, this.details); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment