Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: packages/stack_trace/lib/src/trace.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library trace;
6
7 import 'dart:collection';
8 import 'dart:math' as math; 5 import 'dart:math' as math;
9 6
10 import 'chain.dart'; 7 import 'chain.dart';
11 import 'frame.dart'; 8 import 'frame.dart';
12 import 'lazy_trace.dart'; 9 import 'lazy_trace.dart';
13 import 'unparsed_frame.dart'; 10 import 'unparsed_frame.dart';
14 import 'utils.dart'; 11 import 'utils.dart';
15 import 'vm_trace.dart'; 12 import 'vm_trace.dart';
16 13
17 final _terseRegExp = new RegExp(r"(-patch)?([/\\].*)?$"); 14 final _terseRegExp = new RegExp(r"(-patch)?([/\\].*)?$");
(...skipping 21 matching lines...) Expand all
39 /// error occurred, possibly including its parameters inside `()`. For example, 36 /// error occurred, possibly including its parameters inside `()`. For example,
40 /// `.VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560`. 37 /// `.VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560`.
41 /// 38 ///
42 /// Safari traces occasionally don't include the initial method name followed by 39 /// Safari traces occasionally don't include the initial method name followed by
43 /// "@", and they always have both the line and column number (or just a 40 /// "@", and they always have both the line and column number (or just a
44 /// trailing colon if no column number is available). They can also contain 41 /// trailing colon if no column number is available). They can also contain
45 /// empty lines or lines consisting only of `[native code]`. 42 /// empty lines or lines consisting only of `[native code]`.
46 final _firefoxSafariTrace = new RegExp( 43 final _firefoxSafariTrace = new RegExp(
47 r"^" 44 r"^"
48 r"(" // Member description. Not present in some Safari frames. 45 r"(" // Member description. Not present in some Safari frames.
49 r"([.0-9A-Za-z_$/<]|\(.*\))*" // Member name and arguments. 46 r"([.0-9A-Za-z_$/<]|\(.*\))*" // Member name and arguments.
50 r"@" 47 r"@"
51 r")?" 48 r")?"
52 r"[^\s]*" // Frame URL. 49 r"[^\s]*" // Frame URL.
53 r":\d*" // Line or column number. Some older frames only have a line number. 50 r":\d*" // Line or column number. Some older frames only have a line number.
54 r"$", multiLine: true); 51 r"$",
52 multiLine: true);
55 53
56 /// A RegExp to match this package's stack traces. 54 /// A RegExp to match this package's stack traces.
57 final _friendlyTrace = new RegExp(r"^[^\s]+( \d+(:\d+)?)?[ \t]+[^\s]+$", 55 final _friendlyTrace =
58 multiLine: true); 56 new RegExp(r"^[^\s<][^\s]*( \d+(:\d+)?)?[ \t]+[^\s]+$", multiLine: true);
59 57
60 /// A stack trace, comprised of a list of stack frames. 58 /// A stack trace, comprised of a list of stack frames.
61 class Trace implements StackTrace { 59 class Trace implements StackTrace {
62 /// The stack frames that comprise this stack trace. 60 /// The stack frames that comprise this stack trace.
63 final List<Frame> frames; 61 final List<Frame> frames;
64 62
63 /// The original stack trace from which this trace was parsed.
64 final StackTrace original;
65
65 /// Returns a human-readable representation of [stackTrace]. If [terse] is 66 /// Returns a human-readable representation of [stackTrace]. If [terse] is
66 /// set, this folds together multiple stack frames from the Dart core 67 /// set, this folds together multiple stack frames from the Dart core
67 /// libraries, so that only the core library method directly called from user 68 /// libraries, so that only the core library method directly called from user
68 /// code is visible (see [Trace.terse]). 69 /// code is visible (see [Trace.terse]).
69 static String format(StackTrace stackTrace, {bool terse: true}) { 70 static String format(StackTrace stackTrace, {bool terse: true}) {
70 var trace = new Trace.from(stackTrace); 71 var trace = new Trace.from(stackTrace);
71 if (terse) trace = trace.terse; 72 if (terse) trace = trace.terse;
72 return trace.toString(); 73 return trace.toString();
73 } 74 }
74 75
75 /// Returns the current stack trace. 76 /// Returns the current stack trace.
76 /// 77 ///
77 /// By default, the first frame of this trace will be the line where 78 /// By default, the first frame of this trace will be the line where
78 /// [Trace.current] is called. If [level] is passed, the trace will start that 79 /// [Trace.current] is called. If [level] is passed, the trace will start that
79 /// many frames up instead. 80 /// many frames up instead.
80 factory Trace.current([int level=0]) { 81 factory Trace.current([int level = 0]) {
81 if (level < 0) { 82 if (level < 0) {
82 throw new ArgumentError("Argument [level] must be greater than or equal " 83 throw new ArgumentError("Argument [level] must be greater than or equal "
83 "to 0."); 84 "to 0.");
84 } 85 }
85 86
86 try { 87 var trace = new Trace.from(StackTrace.current);
87 throw ''; 88 return new LazyTrace(() {
88 } catch (_, nativeTrace) { 89 // JS includes a frame for the call to StackTrace.current, but the VM
89 var trace = new Trace.from(nativeTrace); 90 // doesn't, so we skip an extra frame in a JS context.
90 return new LazyTrace(() => new Trace(trace.frames.skip(level + 1))); 91 return new Trace(trace.frames.skip(level + (inJS ? 2 : 1)),
91 } 92 original: trace.original.toString());
93 });
92 } 94 }
93 95
94 /// Returns a new stack trace containing the same data as [trace]. 96 /// Returns a new stack trace containing the same data as [trace].
95 /// 97 ///
96 /// If [trace] is a native [StackTrace], its data will be parsed out; if it's 98 /// If [trace] is a native [StackTrace], its data will be parsed out; if it's
97 /// a [Trace], it will be returned as-is. 99 /// a [Trace], it will be returned as-is.
98 factory Trace.from(StackTrace trace) { 100 factory Trace.from(StackTrace trace) {
99 // Normally explicitly validating null arguments is bad Dart style, but here 101 // Normally explicitly validating null arguments is bad Dart style, but here
100 // the natural failure will only occur when the LazyTrace is materialized, 102 // the natural failure will only occur when the LazyTrace is materialized,
101 // and we want to provide an error that's more local to the actual problem. 103 // and we want to provide an error that's more local to the actual problem.
(...skipping 27 matching lines...) Expand all
129 // Default to parsing the stack trace as a VM trace. This is also hit on 131 // Default to parsing the stack trace as a VM trace. This is also hit on
130 // IE and Safari, where the stack trace is just an empty string (issue 132 // IE and Safari, where the stack trace is just an empty string (issue
131 // 11257). 133 // 11257).
132 return new Trace.parseVM(trace); 134 return new Trace.parseVM(trace);
133 } on FormatException catch (error) { 135 } on FormatException catch (error) {
134 throw new FormatException('${error.message}\nStack trace:\n$trace'); 136 throw new FormatException('${error.message}\nStack trace:\n$trace');
135 } 137 }
136 } 138 }
137 139
138 /// Parses a string representation of a Dart VM stack trace. 140 /// Parses a string representation of a Dart VM stack trace.
139 Trace.parseVM(String trace) 141 Trace.parseVM(String trace) : this(_parseVM(trace), original: trace);
140 : this(_parseVM(trace));
141 142
142 static List<Frame> _parseVM(String trace) { 143 static List<Frame> _parseVM(String trace) {
143 var lines = trace.trim().split("\n"); 144 // Ignore [vmChainGap]. This matches the behavior of
144 var frames = lines.take(lines.length - 1) 145 // `Chain.parse().toTrace()`.
146 var lines = trace.trim().replaceAll(vmChainGap, '').split("\n");
147 var frames = lines
148 .take(lines.length - 1)
145 .map((line) => new Frame.parseVM(line)) 149 .map((line) => new Frame.parseVM(line))
146 .toList(); 150 .toList();
147 151
148 // TODO(nweiz): Remove this when issue 23614 is fixed. 152 // TODO(nweiz): Remove this when issue 23614 is fixed.
149 if (!lines.last.endsWith(".da")) { 153 if (!lines.last.endsWith(".da")) {
150 frames.add(new Frame.parseVM(lines.last)); 154 frames.add(new Frame.parseVM(lines.last));
151 } 155 }
152 156
153 return frames; 157 return frames;
154 } 158 }
155 159
156 /// Parses a string representation of a Chrome/V8 stack trace. 160 /// Parses a string representation of a Chrome/V8 stack trace.
157 Trace.parseV8(String trace) 161 Trace.parseV8(String trace)
158 : this(trace.split("\n").skip(1) 162 : this(
159 // It's possible that an Exception's description contains a line that 163 trace
160 // looks like a V8 trace line, which will screw this up. 164 .split("\n")
161 // Unfortunately, that's impossible to detect. 165 .skip(1)
162 .skipWhile((line) => !line.startsWith(_v8TraceLine)) 166 // It's possible that an Exception's description contains a line that
163 .map((line) => new Frame.parseV8(line))); 167 // looks like a V8 trace line, which will screw this up.
168 // Unfortunately, that's impossible to detect.
169 .skipWhile((line) => !line.startsWith(_v8TraceLine))
170 .map((line) => new Frame.parseV8(line)),
171 original: trace);
164 172
165 /// Parses a string representation of a JavaScriptCore stack trace. 173 /// Parses a string representation of a JavaScriptCore stack trace.
166 Trace.parseJSCore(String trace) 174 Trace.parseJSCore(String trace)
167 : this(trace.split("\n") 175 : this(
168 .where((line) => line != "\tat ") 176 trace
169 .map((line) => new Frame.parseV8(line))); 177 .split("\n")
178 .where((line) => line != "\tat ")
179 .map((line) => new Frame.parseV8(line)),
180 original: trace);
170 181
171 /// Parses a string representation of an Internet Explorer stack trace. 182 /// Parses a string representation of an Internet Explorer stack trace.
172 /// 183 ///
173 /// IE10+ traces look just like V8 traces. Prior to IE10, stack traces can't 184 /// IE10+ traces look just like V8 traces. Prior to IE10, stack traces can't
174 /// be retrieved. 185 /// be retrieved.
175 Trace.parseIE(String trace) 186 Trace.parseIE(String trace) : this.parseV8(trace);
176 : this.parseV8(trace);
177 187
178 /// Parses a string representation of a Firefox stack trace. 188 /// Parses a string representation of a Firefox stack trace.
179 Trace.parseFirefox(String trace) 189 Trace.parseFirefox(String trace)
180 : this(trace.trim().split("\n") 190 : this(
181 .where((line) => line.isNotEmpty && line != '[native code]') 191 trace
182 .map((line) => new Frame.parseFirefox(line))); 192 .trim()
193 .split("\n")
194 .where((line) => line.isNotEmpty && line != '[native code]')
195 .map((line) => new Frame.parseFirefox(line)),
196 original: trace);
183 197
184 /// Parses a string representation of a Safari stack trace. 198 /// Parses a string representation of a Safari stack trace.
185 Trace.parseSafari(String trace) 199 Trace.parseSafari(String trace) : this.parseFirefox(trace);
186 : this.parseFirefox(trace);
187 200
188 /// Parses a string representation of a Safari 6.1+ stack trace. 201 /// Parses a string representation of a Safari 6.1+ stack trace.
189 @Deprecated("Use Trace.parseSafari instead.") 202 @Deprecated("Use Trace.parseSafari instead.")
190 Trace.parseSafari6_1(String trace) 203 Trace.parseSafari6_1(String trace) : this.parseSafari(trace);
191 : this.parseSafari(trace);
192 204
193 /// Parses a string representation of a Safari 6.0 stack trace. 205 /// Parses a string representation of a Safari 6.0 stack trace.
194 @Deprecated("Use Trace.parseSafari instead.") 206 @Deprecated("Use Trace.parseSafari instead.")
195 Trace.parseSafari6_0(String trace) 207 Trace.parseSafari6_0(String trace)
196 : this(trace.trim().split("\n") 208 : this(
197 .where((line) => line != '[native code]') 209 trace
198 .map((line) => new Frame.parseFirefox(line))); 210 .trim()
211 .split("\n")
212 .where((line) => line != '[native code]')
213 .map((line) => new Frame.parseFirefox(line)),
214 original: trace);
199 215
200 /// Parses this package's string representation of a stack trace. 216 /// Parses this package's string representation of a stack trace.
201 /// 217 ///
202 /// This also parses string representations of [Chain]s. They parse to the 218 /// This also parses string representations of [Chain]s. They parse to the
203 /// same trace that [Chain.toTrace] would return. 219 /// same trace that [Chain.toTrace] would return.
204 Trace.parseFriendly(String trace) 220 Trace.parseFriendly(String trace)
205 : this(trace.isEmpty 221 : this(
206 ? [] 222 trace.isEmpty
207 : trace.trim().split("\n") 223 ? []
208 // Filter out asynchronous gaps from [Chain]s. 224 : trace
209 .where((line) => !line.startsWith('=====')) 225 .trim()
210 .map((line) => new Frame.parseFriendly(line))); 226 .split("\n")
227 // Filter out asynchronous gaps from [Chain]s.
228 .where((line) => !line.startsWith('====='))
229 .map((line) => new Frame.parseFriendly(line)),
230 original: trace);
211 231
212 /// Returns a new [Trace] comprised of [frames]. 232 /// Returns a new [Trace] comprised of [frames].
213 Trace(Iterable<Frame> frames) 233 Trace(Iterable<Frame> frames, {String original})
214 : frames = new UnmodifiableListView<Frame>(frames.toList()); 234 : frames = new List<Frame>.unmodifiable(frames),
235 original = new StackTrace.fromString(original);
215 236
216 /// Returns a VM-style [StackTrace] object. 237 /// Returns a VM-style [StackTrace] object.
217 /// 238 ///
218 /// The return value's [toString] method will always return a string 239 /// The return value's [toString] method will always return a string
219 /// representation in the Dart VM's stack trace format, regardless of what 240 /// representation in the Dart VM's stack trace format, regardless of what
220 /// platform is being used. 241 /// platform is being used.
221 StackTrace get vmTrace => new VMTrace(frames); 242 StackTrace get vmTrace => new VMTrace(frames);
222 243
223 /// Returns a terser version of [this]. 244 /// Returns a terser version of [this].
224 /// 245 ///
225 /// This is accomplished by folding together multiple stack frames from the 246 /// This is accomplished by folding together multiple stack frames from the
226 /// core library or from this package, as in [foldFrames]. Remaining core 247 /// core library or from this package, as in [foldFrames]. Remaining core
227 /// library frames have their libraries, "-patch" suffixes, and line numbers 248 /// library frames have their libraries, "-patch" suffixes, and line numbers
228 /// removed. If the outermost frame of the stack trace is a core library 249 /// removed. If the outermost frame of the stack trace is a core library
229 /// frame, it's removed entirely. 250 /// frame, it's removed entirely.
230 /// 251 ///
252 /// This won't do anything with a raw JavaScript trace, since there's no way
253 /// to determine which frames come from which Dart libraries. However, the
254 /// [`source_map_stack_trace`][source_map_stack_trace] package can be used to
255 /// convert JavaScript traces into Dart-style traces.
256 ///
257 /// [source_map_stack_trace]: https://pub.dartlang.org/packages/source_map_sta ck_trace
258 ///
231 /// For custom folding, see [foldFrames]. 259 /// For custom folding, see [foldFrames].
232 Trace get terse => foldFrames((_) => false, terse: true); 260 Trace get terse => foldFrames((_) => false, terse: true);
233 261
234 /// Returns a new [Trace] based on [this] where multiple stack frames matching 262 /// Returns a new [Trace] based on [this] where multiple stack frames matching
235 /// [predicate] are folded together. 263 /// [predicate] are folded together.
236 /// 264 ///
237 /// This means that whenever there are multiple frames in a row that match 265 /// This means that whenever there are multiple frames in a row that match
238 /// [predicate], only the last one is kept. This is useful for limiting the 266 /// [predicate], only the last one is kept. This is useful for limiting the
239 /// amount of library code that appears in a stack trace by only showing user 267 /// amount of library code that appears in a stack trace by only showing user
240 /// code and code that's called by user code. 268 /// code and code that's called by user code.
(...skipping 15 matching lines...) Expand all
256 // internal frames. They only ever show up in stack chains and are 284 // internal frames. They only ever show up in stack chains and are
257 // always surrounded by other traces that are actually useful, so we can 285 // always surrounded by other traces that are actually useful, so we can
258 // just get rid of them. 286 // just get rid of them.
259 // TODO(nweiz): Get rid of this logic some time after issue 22009 is 287 // TODO(nweiz): Get rid of this logic some time after issue 22009 is
260 // fixed. 288 // fixed.
261 if (!frame.member.contains('<async>')) return false; 289 if (!frame.member.contains('<async>')) return false;
262 return frame.line == null; 290 return frame.line == null;
263 }; 291 };
264 } 292 }
265 293
266 var newFrames = []; 294 var newFrames = <Frame>[];
267 for (var frame in frames.reversed) { 295 for (var frame in frames.reversed) {
268 if (frame is UnparsedFrame || !predicate(frame)) { 296 if (frame is UnparsedFrame || !predicate(frame)) {
269 newFrames.add(frame); 297 newFrames.add(frame);
270 } else if (newFrames.isEmpty || !predicate(newFrames.last)) { 298 } else if (newFrames.isEmpty || !predicate(newFrames.last)) {
271 newFrames.add(new Frame( 299 newFrames
272 frame.uri, frame.line, frame.column, frame.member)); 300 .add(new Frame(frame.uri, frame.line, frame.column, frame.member));
273 } 301 }
274 } 302 }
275 303
276 if (terse) { 304 if (terse) {
277 newFrames = newFrames.map((frame) { 305 newFrames = newFrames.map((frame) {
278 if (frame is UnparsedFrame || !predicate(frame)) return frame; 306 if (frame is UnparsedFrame || !predicate(frame)) return frame;
279 var library = frame.library.replaceAll(_terseRegExp, ''); 307 var library = frame.library.replaceAll(_terseRegExp, '');
280 return new Frame(Uri.parse(library), null, null, frame.member); 308 return new Frame(Uri.parse(library), null, null, frame.member);
281 }).toList(); 309 }).toList();
282 if (newFrames.length > 1 && newFrames.first.isCore) newFrames.removeAt(0); 310
311 if (newFrames.length > 1 && predicate(newFrames.first)) {
312 newFrames.removeAt(0);
313 }
283 } 314 }
284 315
285 return new Trace(newFrames.reversed); 316 return new Trace(newFrames.reversed, original: this.original.toString());
286 } 317 }
287 318
288 /// Returns a human-readable string representation of [this]. 319 /// Returns a human-readable string representation of [this].
289 String toString() { 320 String toString() {
290 // Figure out the longest path so we know how much to pad. 321 // Figure out the longest path so we know how much to pad.
291 var longest = frames.map((frame) => frame.location.length) 322 var longest =
292 .fold(0, math.max); 323 frames.map((frame) => frame.location.length).fold(0, math.max);
293 324
294 // Print out the stack trace nicely formatted. 325 // Print out the stack trace nicely formatted.
295 return frames.map((frame) { 326 return frames.map((frame) {
296 if (frame is UnparsedFrame) return "$frame\n"; 327 if (frame is UnparsedFrame) return "$frame\n";
297 return '${padRight(frame.location, longest)} ${frame.member}\n'; 328 return '${frame.location.padRight(longest)} ${frame.member}\n';
298 }).join(); 329 }).join();
299 } 330 }
300 } 331 }
OLDNEW
« no previous file with comments | « packages/stack_trace/lib/src/stack_zone_specification.dart ('k') | packages/stack_trace/lib/src/unparsed_frame.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698