OLD | NEW |
(Empty) | |
| 1 This library provides the ability to parse, inspect, and manipulate stack traces |
| 2 produced by the underlying Dart implementation. It also provides functions to |
| 3 produce string representations of stack traces in a more readable format than |
| 4 the native [StackTrace] implementation. |
| 5 |
| 6 `Trace`s can be parsed from native [StackTrace]s using `Trace.from`, or captured |
| 7 using `Trace.current`. Native [StackTrace]s can also be directly converted to |
| 8 human-readable strings using `Trace.format`. |
| 9 |
| 10 [StackTrace]: http://api.dartlang.org/docs/releases/latest/dart_core/StackTrace.
html |
| 11 |
| 12 Here's an example native stack trace from debugging this library: |
| 13 |
| 14 #0 Object.noSuchMethod (dart:core-patch:1884:25) |
| 15 #1 Trace.terse.<anonymous closure> (file:///usr/local/google-old/home/g
oog/dart/dart/pkg/stack_trace/lib/src/trace.dart:47:21) |
| 16 #2 IterableMixinWorkaround.reduce (dart:collection:29:29) |
| 17 #3 List.reduce (dart:core-patch:1247:42) |
| 18 #4 Trace.terse (file:///usr/local/google-old/home/goog/dart/dart/pkg/st
ack_trace/lib/src/trace.dart:40:35) |
| 19 #5 format (file:///usr/local/google-old/home/goog/dart/dart/pkg/stack_t
race/lib/stack_trace.dart:24:28) |
| 20 #6 main.<anonymous closure> (file:///usr/local/google-old/home/goog/dar
t/dart/test.dart:21:29) |
| 21 #7 _CatchErrorFuture._sendError (dart:async:525:24) |
| 22 #8 _FutureImpl._setErrorWithoutAsyncTrace (dart:async:393:26) |
| 23 #9 _FutureImpl._setError (dart:async:378:31) |
| 24 #10 _ThenFuture._sendValue (dart:async:490:16) |
| 25 #11 _FutureImpl._handleValue.<anonymous closure> (dart:async:349:28) |
| 26 #12 Timer.run.<anonymous closure> (dart:async:2402:21) |
| 27 #13 Timer.Timer.<anonymous closure> (dart:async-patch:15:15) |
| 28 |
| 29 and its human-readable representation: |
| 30 |
| 31 dart:core-patch Object.noSuchMethod |
| 32 pkg/stack_trace/lib/src/trace.dart 47:21 Trace.terse.<fn> |
| 33 dart:collection IterableMixinWorkaround.reduce |
| 34 dart:core-patch List.reduce |
| 35 pkg/stack_trace/lib/src/trace.dart 40:35 Trace.terse |
| 36 pkg/stack_trace/lib/stack_trace.dart 24:28 format |
| 37 test.dart 21:29 main.<fn> |
| 38 dart:async _CatchErrorFuture._sendError |
| 39 dart:async _FutureImpl._setErrorWithoutAsyn
cTrace |
| 40 dart:async _FutureImpl._setError |
| 41 dart:async _ThenFuture._sendValue |
| 42 dart:async _FutureImpl._handleValue.<fn> |
| 43 dart:async Timer.run.<fn> |
| 44 dart:async-patch Timer.Timer.<fn> |
| 45 |
| 46 You can further clean up the stack trace using `Trace.terse`. This folds |
| 47 together multiple stack frames from the Dart core libraries, so that only the |
| 48 core library method that was directly called from user code is visible. For |
| 49 example: |
| 50 |
| 51 dart:core Object.noSuchMethod |
| 52 pkg/stack_trace/lib/src/trace.dart 47:21 Trace.terse.<fn> |
| 53 dart:core List.reduce |
| 54 pkg/stack_trace/lib/src/trace.dart 40:35 Trace.terse |
| 55 pkg/stack_trace/lib/stack_trace.dart 24:28 format |
| 56 test.dart 21:29 main.<fn> |
| 57 |
| 58 ## Stack Chains |
| 59 |
| 60 This library also provides the ability to capture "stack chains" with the |
| 61 `Chain` class. When writing asynchronous code, a single stack trace isn't very |
| 62 useful, since the call stack is unwound every time something async happens. A |
| 63 stack chain tracks stack traces through asynchronous calls, so that you can see |
| 64 the full path from `main` down to the error. |
| 65 |
| 66 To use stack chains, just wrap the code that you want to track in |
| 67 `Chain.capture`. This will create a new [Zone][] in which stack traces are |
| 68 recorded and woven into chains every time an asynchronous call occurs. Zones are |
| 69 sticky, too, so any asynchronous operations started in the `Chain.capture` |
| 70 callback will have their chains tracked, as will asynchronous operations they |
| 71 start and so on. |
| 72 |
| 73 Here's an example of some code that doesn't capture its stack chains: |
| 74 |
| 75 ```dart |
| 76 import 'dart:async'; |
| 77 |
| 78 void main() { |
| 79 scheduleAsync(); |
| 80 } |
| 81 |
| 82 void scheduleAsync() { |
| 83 return new Future.delayed(new Duration(seconds: 1)) |
| 84 .then((_) => runAsync()); |
| 85 } |
| 86 |
| 87 void runAsync() { |
| 88 throw 'oh no!'; |
| 89 } |
| 90 ``` |
| 91 |
| 92 If we run this, it prints the following: |
| 93 |
| 94 Uncaught Error: oh no! |
| 95 Stack Trace: |
| 96 #0 runAsync (file:///usr/local/google-old/home/goog/dart/dart/test.dart
:13:3) |
| 97 #1 scheduleAsync.<anonymous closure> (file:///usr/local/google-old/home
/goog/dart/dart/test.dart:9:28) |
| 98 #2 _rootRunUnary (dart:async/zone.dart:717) |
| 99 #3 _RootZone.runUnary (dart:async/zone.dart:854) |
| 100 #4 _Future._propagateToListeners.handleValueCallback (dart:async/future
_impl.dart:488) |
| 101 #5 _Future._propagateToListeners (dart:async/future_impl.dart:571) |
| 102 #6 _Future._complete (dart:async/future_impl.dart:317) |
| 103 #7 _SyncCompleter.complete (dart:async/future_impl.dart:44) |
| 104 #8 Future.Future.delayed.<anonymous closure> (dart:async/future.dart:21
9) |
| 105 #9 _createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:
11) |
| 106 #10 _handleTimeout (dart:io/timer_impl.dart:292) |
| 107 #11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch
.dart:115) |
| 108 |
| 109 Notice how there's no mention of `main` in that stack trace. All we know is that |
| 110 the error was in `runAsync`; we don't know why `runAsync` was called. |
| 111 |
| 112 Now let's look at the same code with stack chains captured: |
| 113 |
| 114 ```dart |
| 115 import 'dart:async'; |
| 116 |
| 117 import 'package:stack_trace/stack_trace.dart'; |
| 118 |
| 119 void main() { |
| 120 Chain.capture(() { |
| 121 scheduleAsync(); |
| 122 }); |
| 123 } |
| 124 |
| 125 void scheduleAsync() { |
| 126 new Future.delayed(new Duration(seconds: 1)) |
| 127 .then((_) => runAsync()); |
| 128 } |
| 129 |
| 130 void runAsync() { |
| 131 throw 'oh no!'; |
| 132 } |
| 133 ``` |
| 134 |
| 135 Now if we run it, it prints this: |
| 136 |
| 137 Uncaught Error: oh no! |
| 138 Stack Trace: |
| 139 test.dart 17:3 runAsync |
| 140 test.dart 13:28 scheduleAsync.
<fn> |
| 141 package:stack_trace/src/stack_zone_specification.dart 129:26 registerUnaryC
allback.<fn>.<fn> |
| 142 package:stack_trace/src/stack_zone_specification.dart 174:15 StackZoneSpeci
fication._run |
| 143 package:stack_trace/src/stack_zone_specification.dart 177:7 StackZoneSpeci
fication._run |
| 144 package:stack_trace/src/stack_zone_specification.dart 175:7 StackZoneSpeci
fication._run |
| 145 package:stack_trace/src/stack_zone_specification.dart 129:18 registerUnaryC
allback.<fn> |
| 146 dart:async/zone.dart 717 _rootRunUnary |
| 147 dart:async/zone.dart 449 _ZoneDelegate.
runUnary |
| 148 dart:async/zone.dart 654 _CustomizedZon
e.runUnary |
| 149 dart:async/future_impl.dart 488 _Future._propa
gateToListeners.handleValueCallback |
| 150 dart:async/future_impl.dart 571 _Future._propa
gateToListeners |
| 151 dart:async/future_impl.dart 317 _Future._compl
ete |
| 152 dart:async/future_impl.dart 44 _SyncCompleter
.complete |
| 153 dart:async/future.dart 219 Future.Future.
delayed.<fn> |
| 154 package:stack_trace/src/stack_zone_specification.dart 174:15 StackZoneSpeci
fication._run |
| 155 package:stack_trace/src/stack_zone_specification.dart 119:52 registerCallba
ck.<fn> |
| 156 dart:async/zone.dart 706 _rootRun |
| 157 dart:async/zone.dart 440 _ZoneDelegate.
run |
| 158 dart:async/zone.dart 650 _CustomizedZon
e.run |
| 159 dart:async/zone.dart 561 _BaseZone.runG
uarded |
| 160 dart:async/zone.dart 586 _BaseZone.bind
Callback.<fn> |
| 161 package:stack_trace/src/stack_zone_specification.dart 174:15 StackZoneSpeci
fication._run |
| 162 package:stack_trace/src/stack_zone_specification.dart 119:52 registerCallba
ck.<fn> |
| 163 dart:async/zone.dart 710 _rootRun |
| 164 dart:async/zone.dart 440 _ZoneDelegate.
run |
| 165 dart:async/zone.dart 650 _CustomizedZon
e.run |
| 166 dart:async/zone.dart 561 _BaseZone.runG
uarded |
| 167 dart:async/zone.dart 586 _BaseZone.bind
Callback.<fn> |
| 168 dart:async-patch/timer_patch.dart 11 _createTimer.<
fn> |
| 169 dart:io/timer_impl.dart 292 _handleTimeout |
| 170 dart:isolate-patch/isolate_patch.dart 115 _RawReceivePor
tImpl._handleMessage |
| 171 ===== asynchronous gap =========================== |
| 172 dart:async/zone.dart 476 _ZoneDelegate.
registerUnaryCallback |
| 173 dart:async/zone.dart 666 _CustomizedZon
e.registerUnaryCallback |
| 174 dart:async/future_impl.dart 164 _Future._Futur
e._then |
| 175 dart:async/future_impl.dart 187 _Future.then |
| 176 test.dart 13:12 scheduleAsync |
| 177 test.dart 7:18 main.<fn> |
| 178 dart:async/zone.dart 710 _rootRun |
| 179 dart:async/zone.dart 440 _ZoneDelegate.
run |
| 180 dart:async/zone.dart 650 _CustomizedZon
e.run |
| 181 dart:async/zone.dart 944 runZoned |
| 182 package:stack_trace/src/chain.dart 93:20 Chain.capture |
| 183 test.dart 6:16 main |
| 184 dart:isolate-patch/isolate_patch.dart 216 _startIsolate.
isolateStartHandler |
| 185 dart:isolate-patch/isolate_patch.dart 115 _RawReceivePor
tImpl._handleMessage |
| 186 |
| 187 That's a lot of text! If you look closely, though, you can see that `main` is |
| 188 listed in the first trace in the chain. |
| 189 |
| 190 Thankfully, you can call `Chain.terse` just like `Trace.terse` to get rid of all |
| 191 the frames you don't care about. The terse version of the stack chain above is |
| 192 this: |
| 193 |
| 194 test.dart 17:3 runAsync |
| 195 test.dart 13:28 scheduleAsync.<fn> |
| 196 ===== asynchronous gap =========================== |
| 197 dart:async _Future.then |
| 198 test.dart 13:12 scheduleAsync |
| 199 test.dart 7:18 main.<fn> |
| 200 package:stack_trace Chain.capture |
| 201 test.dart 6:16 main |
| 202 |
| 203 That's a lot easier to understand! |
| 204 |
| 205 [Zone]: https://api.dartlang.org/apidocs/channels/stable/#dart-async.Zone |
OLD | NEW |