OLD | NEW |
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; | 5 library trace; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:math' as math; | 8 import 'dart:math' as math; |
9 | 9 |
10 import 'chain.dart'; | 10 import 'chain.dart'; |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 /// representation in the Dart VM's stack trace format, regardless of what | 196 /// representation in the Dart VM's stack trace format, regardless of what |
197 /// platform is being used. | 197 /// platform is being used. |
198 StackTrace get vmTrace => new VMTrace(frames); | 198 StackTrace get vmTrace => new VMTrace(frames); |
199 | 199 |
200 /// Returns a terser version of [this]. | 200 /// Returns a terser version of [this]. |
201 /// | 201 /// |
202 /// This is accomplished by folding together multiple stack frames from the | 202 /// This is accomplished by folding together multiple stack frames from the |
203 /// core library or from this package, as in [foldFrames]. Remaining core | 203 /// core library or from this package, as in [foldFrames]. Remaining core |
204 /// library frames have their libraries, "-patch" suffixes, and line numbers | 204 /// library frames have their libraries, "-patch" suffixes, and line numbers |
205 /// removed. | 205 /// removed. |
206 Trace get terse { | 206 /// |
207 return new Trace(foldFrames((frame) { | 207 /// For custom folding, see [foldFrames]. |
208 if (frame.isCore) return true; | 208 Trace get terse => foldFrames((_) => false, terse: true); |
209 if (frame.package == 'stack_trace') return true; | |
210 | |
211 // Ignore async stack frames without any line or column information. These | |
212 // come from the VM's async/await implementation and represent internal | |
213 // frames. They only ever show up in stack chains and are always | |
214 // surrounded by other traces that are actually useful, so we can just get | |
215 // rid of them. | |
216 // TODO(nweiz): Get rid of this logic some time after issue 22009 is | |
217 // fixed. | |
218 if (!frame.member.contains('<async>')) return false; | |
219 return frame.line == null; | |
220 }).frames.map((frame) { | |
221 if (!frame.isCore) return frame; | |
222 var library = frame.library.replaceAll(_terseRegExp, ''); | |
223 return new Frame(Uri.parse(library), null, null, frame.member); | |
224 })); | |
225 } | |
226 | 209 |
227 /// Returns a new [Trace] based on [this] where multiple stack frames matching | 210 /// Returns a new [Trace] based on [this] where multiple stack frames matching |
228 /// [predicate] are folded together. This means that whenever there are | 211 /// [predicate] are folded together. |
229 /// multiple frames in a row that match [predicate], only the last one is | |
230 /// kept. | |
231 /// | 212 /// |
232 /// This is useful for limiting the amount of library code that appears in a | 213 /// This means that whenever there are multiple frames in a row that match |
233 /// stack trace by only showing user code and code that's called by user code. | 214 /// [predicate], only the last one is kept. This is useful for limiting the |
234 Trace foldFrames(bool predicate(Frame frame)) { | 215 /// amount of library code that appears in a stack trace by only showing user |
235 var newFrames = <Frame>[]; | 216 /// code and code that's called by user code. |
| 217 /// |
| 218 /// If [terse] is true, this will also fold together frames from the core |
| 219 /// library or from this package, and simplify core library frames as in |
| 220 /// [Trace.terse]. |
| 221 Trace foldFrames(bool predicate(Frame frame), {bool terse: false}) { |
| 222 if (terse) { |
| 223 var oldPredicate = predicate; |
| 224 predicate = (frame) { |
| 225 if (oldPredicate(frame)) return true; |
| 226 |
| 227 if (frame.isCore) return true; |
| 228 if (frame.package == 'stack_trace') return true; |
| 229 |
| 230 // Ignore async stack frames without any line or column information. |
| 231 // These come from the VM's async/await implementation and represent |
| 232 // internal frames. They only ever show up in stack chains and are |
| 233 // always surrounded by other traces that are actually useful, so we can |
| 234 // just get rid of them. |
| 235 // TODO(nweiz): Get rid of this logic some time after issue 22009 is |
| 236 // fixed. |
| 237 if (!frame.member.contains('<async>')) return false; |
| 238 return frame.line == null; |
| 239 }; |
| 240 } |
| 241 |
| 242 var newFrames = []; |
236 for (var frame in frames.reversed) { | 243 for (var frame in frames.reversed) { |
237 if (!predicate(frame)) { | 244 if (!predicate(frame)) { |
238 newFrames.add(frame); | 245 newFrames.add(frame); |
239 } else if (newFrames.isEmpty || !predicate(newFrames.last)) { | 246 } else if (newFrames.isEmpty || !predicate(newFrames.last)) { |
240 newFrames.add(new Frame( | 247 newFrames.add(new Frame( |
241 frame.uri, frame.line, frame.column, frame.member)); | 248 frame.uri, frame.line, frame.column, frame.member)); |
242 } | 249 } |
243 } | 250 } |
244 | 251 |
| 252 if (terse) { |
| 253 newFrames = newFrames.map((frame) { |
| 254 if (!frame.isCore) return frame; |
| 255 var library = frame.library.replaceAll(_terseRegExp, ''); |
| 256 return new Frame(Uri.parse(library), null, null, frame.member); |
| 257 }).toList(); |
| 258 } |
| 259 |
245 return new Trace(newFrames.reversed); | 260 return new Trace(newFrames.reversed); |
246 } | 261 } |
247 | 262 |
248 /// Returns a human-readable string representation of [this]. | 263 /// Returns a human-readable string representation of [this]. |
249 String toString() { | 264 String toString() { |
250 // Figure out the longest path so we know how much to pad. | 265 // Figure out the longest path so we know how much to pad. |
251 var longest = frames.map((frame) => frame.location.length) | 266 var longest = frames.map((frame) => frame.location.length) |
252 .fold(0, math.max); | 267 .fold(0, math.max); |
253 | 268 |
254 // Print out the stack trace nicely formatted. | 269 // Print out the stack trace nicely formatted. |
255 return frames.map((frame) { | 270 return frames.map((frame) { |
256 return '${padRight(frame.location, longest)} ${frame.member}\n'; | 271 return '${padRight(frame.location, longest)} ${frame.member}\n'; |
257 }).join(); | 272 }).join(); |
258 } | 273 } |
259 } | 274 } |
OLD | NEW |