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

Side by Side Diff: packages/stack_trace/lib/src/stack_zone_specification.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
« no previous file with comments | « packages/stack_trace/lib/src/lazy_trace.dart ('k') | packages/stack_trace/lib/src/trace.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 stack_trace.stack_zone_specification;
6
7 import 'dart:async'; 5 import 'dart:async';
8 6
7 import 'chain.dart';
8 import 'lazy_trace.dart';
9 import 'trace.dart'; 9 import 'trace.dart';
10 import 'chain.dart'; 10 import 'utils.dart';
11
12 /// A function that handles errors in the zone wrapped by [Chain.capture].
13 typedef void _ChainHandler(error, Chain chain);
11 14
12 /// A class encapsulating the zone specification for a [Chain.capture] zone. 15 /// A class encapsulating the zone specification for a [Chain.capture] zone.
13 /// 16 ///
14 /// Until they're materialized and exposed to the user, stack chains are tracked 17 /// Until they're materialized and exposed to the user, stack chains are tracked
15 /// as linked lists of [Trace]s using the [_Node] class. These nodes are stored 18 /// as linked lists of [Trace]s using the [_Node] class. These nodes are stored
16 /// in three distinct ways: 19 /// in three distinct ways:
17 /// 20 ///
18 /// * When a callback is registered, a node is created and stored as a captured 21 /// * When a callback is registered, a node is created and stored as a captured
19 /// local variable until the callback is run. 22 /// local variable until the callback is run.
20 /// 23 ///
21 /// * When a callback is run, its captured node is set as the [_currentNode] so 24 /// * When a callback is run, its captured node is set as the [_currentNode] so
22 /// it can be available to [Chain.current] and to be linked into additional 25 /// it can be available to [Chain.current] and to be linked into additional
23 /// chains when more callbacks are scheduled. 26 /// chains when more callbacks are scheduled.
24 /// 27 ///
25 /// * When a callback throws an error or a Future or Stream emits an error, the 28 /// * When a callback throws an error or a Future or Stream emits an error, the
26 /// current node is associated with that error's stack trace using the 29 /// current node is associated with that error's stack trace using the
27 /// [_chains] expando. 30 /// [_chains] expando.
28 /// 31 ///
29 /// Since [ZoneSpecification] can't be extended or even implemented, in order to 32 /// Since [ZoneSpecification] can't be extended or even implemented, in order to
30 /// get a real [ZoneSpecification] instance it's necessary to call [toSpec]. 33 /// get a real [ZoneSpecification] instance it's necessary to call [toSpec].
31 class StackZoneSpecification { 34 class StackZoneSpecification {
35 /// An opaque object used as a zone value to disable chain tracking in a given
36 /// zone.
37 ///
38 /// If `Zone.current[disableKey]` is `true`, no stack chains will be tracked.
39 static final disableKey = new Object();
40
41 /// Whether chain-tracking is disabled in the current zone.
42 bool get _disabled => Zone.current[disableKey] == true;
43
32 /// The expando that associates stack chains with [StackTrace]s. 44 /// The expando that associates stack chains with [StackTrace]s.
33 /// 45 ///
34 /// The chains are associated with stack traces rather than errors themselves 46 /// The chains are associated with stack traces rather than errors themselves
35 /// because it's a common practice to throw strings as errors, which can't be 47 /// because it's a common practice to throw strings as errors, which can't be
36 /// used with expandos. 48 /// used with expandos.
37 /// 49 ///
38 /// The chain associated with a given stack trace doesn't contain a node for 50 /// The chain associated with a given stack trace doesn't contain a node for
39 /// that stack trace. 51 /// that stack trace.
40 final _chains = new Expando<_Node>("stack chains"); 52 final _chains = new Expando<_Node>("stack chains");
41 53
42 /// The error handler for the zone. 54 /// The error handler for the zone.
43 /// 55 ///
44 /// If this is null, that indicates that any unhandled errors should be passed 56 /// If this is null, that indicates that any unhandled errors should be passed
45 /// to the parent zone. 57 /// to the parent zone.
46 final ChainHandler _onError; 58 final _ChainHandler _onError;
47 59
48 /// The most recent node of the current stack chain. 60 /// The most recent node of the current stack chain.
49 _Node _currentNode; 61 _Node _currentNode;
50 62
51 StackZoneSpecification([this._onError]); 63 StackZoneSpecification([this._onError]);
52 64
53 /// Converts [this] to a real [ZoneSpecification]. 65 /// Converts [this] to a real [ZoneSpecification].
54 ZoneSpecification toSpec() { 66 ZoneSpecification toSpec() {
55 return new ZoneSpecification( 67 return new ZoneSpecification(
56 handleUncaughtError: handleUncaughtError, 68 handleUncaughtError: _handleUncaughtError,
57 registerCallback: registerCallback, 69 registerCallback: _registerCallback,
58 registerUnaryCallback: registerUnaryCallback, 70 registerUnaryCallback: _registerUnaryCallback,
59 registerBinaryCallback: registerBinaryCallback, 71 registerBinaryCallback: _registerBinaryCallback,
60 errorCallback: errorCallback); 72 errorCallback: _errorCallback);
61 } 73 }
62 74
63 /// Returns the current stack chain. 75 /// Returns the current stack chain.
64 /// 76 ///
65 /// By default, the first frame of the first trace will be the line where 77 /// By default, the first frame of the first trace will be the line where
66 /// [currentChain] is called. If [level] is passed, the first trace will start 78 /// [currentChain] is called. If [level] is passed, the first trace will start
67 /// that many frames up instead. 79 /// that many frames up instead.
68 Chain currentChain([int level=0]) => _createNode(level + 1).toChain(); 80 Chain currentChain([int level = 0]) => _createNode(level + 1).toChain();
69 81
70 /// Returns the stack chain associated with [trace], if one exists. 82 /// Returns the stack chain associated with [trace], if one exists.
71 /// 83 ///
72 /// The first stack trace in the returned chain will always be [trace] 84 /// The first stack trace in the returned chain will always be [trace]
73 /// (converted to a [Trace] if necessary). If there is no chain associated 85 /// (converted to a [Trace] if necessary). If there is no chain associated
74 /// with [trace], this just returns a single-trace chain containing [trace]. 86 /// with [trace], this just returns a single-trace chain containing [trace].
75 Chain chainFor(StackTrace trace) { 87 Chain chainFor(StackTrace trace) {
76 if (trace is Chain) return trace; 88 if (trace is Chain) return trace;
77 var previous = trace == null ? null : _chains[trace]; 89 var previous = trace == null ? null : _chains[trace];
78 return new _Node(trace, previous).toChain(); 90 return new _Node(trace, previous).toChain();
79 } 91 }
80 92
81 /// Ensures that an error emitted by [future] has the correct stack
82 /// information associated with it.
83 ///
84 /// By default, the first frame of the first trace will be the line where
85 /// [trackFuture] is called. If [level] is passed, the first trace will start
86 /// that many frames up instead.
87 Future trackFuture(Future future, [int level=0]) {
88 var completer = new Completer.sync();
89 var node = _createNode(level + 1);
90 future.then(completer.complete).catchError((e, stackTrace) {
91 if (stackTrace == null) stackTrace = new Trace.current();
92 if (stackTrace is! Chain && _chains[stackTrace] == null) {
93 _chains[stackTrace] = node;
94 }
95 completer.completeError(e, stackTrace);
96 });
97 return completer.future;
98 }
99
100 /// Ensures that any errors emitted by [stream] have the correct stack
101 /// information associated with them.
102 ///
103 /// By default, the first frame of the first trace will be the line where
104 /// [trackStream] is called. If [level] is passed, the first trace will start
105 /// that many frames up instead.
106 Stream trackStream(Stream stream, [int level=0]) {
107 var node = _createNode(level + 1);
108 return stream.transform(new StreamTransformer.fromHandlers(
109 handleError: (error, stackTrace, sink) {
110 if (stackTrace == null) stackTrace = new Trace.current();
111 if (stackTrace is! Chain && _chains[stackTrace] == null) {
112 _chains[stackTrace] = node;
113 }
114 sink.addError(error, stackTrace);
115 }));
116 }
117
118 /// Tracks the current stack chain so it can be set to [_currentChain] when 93 /// Tracks the current stack chain so it can be set to [_currentChain] when
119 /// [f] is run. 94 /// [f] is run.
120 ZoneCallback registerCallback(Zone self, ZoneDelegate parent, Zone zone, 95 ZoneCallback _registerCallback(
121 Function f) { 96 Zone self, ZoneDelegate parent, Zone zone, Function f) {
122 if (f == null) return parent.registerCallback(zone, null); 97 if (f == null || _disabled) return parent.registerCallback(zone, f);
123 var node = _createNode(1); 98 var node = _createNode(1);
124 return parent.registerCallback(zone, () => _run(f, node)); 99 return parent.registerCallback(zone, () => _run(f, node));
125 } 100 }
126 101
127 /// Tracks the current stack chain so it can be set to [_currentChain] when 102 /// Tracks the current stack chain so it can be set to [_currentChain] when
128 /// [f] is run. 103 /// [f] is run.
129 ZoneUnaryCallback registerUnaryCallback(Zone self, ZoneDelegate parent, 104 ZoneUnaryCallback _registerUnaryCallback(
130 Zone zone, Function f) { 105 Zone self, ZoneDelegate parent, Zone zone, Function f) {
131 if (f == null) return parent.registerUnaryCallback(zone, null); 106 if (f == null || _disabled) return parent.registerUnaryCallback(zone, f);
132 var node = _createNode(1); 107 var node = _createNode(1);
133 return parent.registerUnaryCallback(zone, (arg) { 108 return parent.registerUnaryCallback(zone, (arg) {
134 return _run(() => f(arg), node); 109 return _run(() => f(arg), node);
135 }); 110 });
136 } 111 }
137 112
138 /// Tracks the current stack chain so it can be set to [_currentChain] when 113 /// Tracks the current stack chain so it can be set to [_currentChain] when
139 /// [f] is run. 114 /// [f] is run.
140 ZoneBinaryCallback registerBinaryCallback(Zone self, ZoneDelegate parent, 115 ZoneBinaryCallback _registerBinaryCallback(
141 Zone zone, Function f) { 116 Zone self, ZoneDelegate parent, Zone zone, Function f) {
142 if (f == null) return parent.registerBinaryCallback(zone, null); 117 if (f == null || _disabled) return parent.registerBinaryCallback(zone, f);
118
143 var node = _createNode(1); 119 var node = _createNode(1);
144 return parent.registerBinaryCallback(zone, (arg1, arg2) { 120 return parent.registerBinaryCallback(zone, (arg1, arg2) {
145 return _run(() => f(arg1, arg2), node); 121 return _run(() => f(arg1, arg2), node);
146 }); 122 });
147 } 123 }
148 124
149 /// Looks up the chain associated with [stackTrace] and passes it either to 125 /// Looks up the chain associated with [stackTrace] and passes it either to
150 /// [_onError] or [parent]'s error handler. 126 /// [_onError] or [parent]'s error handler.
151 handleUncaughtError(Zone self, ZoneDelegate parent, Zone zone, error, 127 _handleUncaughtError(
152 StackTrace stackTrace) { 128 Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
129 if (_disabled) {
130 return parent.handleUncaughtError(zone, error, stackTrace);
131 }
132
153 var stackChain = chainFor(stackTrace); 133 var stackChain = chainFor(stackTrace);
154 if (_onError == null) { 134 if (_onError == null) {
155 return parent.handleUncaughtError(zone, error, stackChain); 135 return parent.handleUncaughtError(zone, error, stackChain);
156 } 136 }
157 137
158 // TODO(nweiz): Currently this copies a lot of logic from [runZoned]. Just 138 // TODO(nweiz): Currently this copies a lot of logic from [runZoned]. Just
159 // allow [runBinary] to throw instead once issue 18134 is fixed. 139 // allow [runBinary] to throw instead once issue 18134 is fixed.
160 try { 140 try {
161 return parent.runBinary(zone, _onError, error, stackChain); 141 return self.parent.runBinary(_onError, error, stackChain);
162 } catch (newError, newStackTrace) { 142 } catch (newError, newStackTrace) {
163 if (identical(newError, error)) { 143 if (identical(newError, error)) {
164 return parent.handleUncaughtError(zone, error, stackChain); 144 return parent.handleUncaughtError(zone, error, stackChain);
165 } else { 145 } else {
166 return parent.handleUncaughtError(zone, newError, newStackTrace); 146 return parent.handleUncaughtError(zone, newError, newStackTrace);
167 } 147 }
168 } 148 }
169 } 149 }
170 150
171 /// Attaches the current stack chain to [stackTrace], replacing it if 151 /// Attaches the current stack chain to [stackTrace], replacing it if
172 /// necessary. 152 /// necessary.
173 AsyncError errorCallback(Zone self, ZoneDelegate parent, Zone zone, 153 AsyncError _errorCallback(Zone self, ZoneDelegate parent, Zone zone,
174 Object error, StackTrace stackTrace) { 154 Object error, StackTrace stackTrace) {
155 if (_disabled) return parent.errorCallback(zone, error, stackTrace);
156
175 // Go up two levels to get through [_CustomZone.errorCallback]. 157 // Go up two levels to get through [_CustomZone.errorCallback].
176 if (stackTrace == null) { 158 if (stackTrace == null) {
177 stackTrace = _createNode(2).toChain(); 159 stackTrace = _createNode(2).toChain();
178 } else { 160 } else {
179 if (_chains[stackTrace] == null) _chains[stackTrace] = _createNode(2); 161 if (_chains[stackTrace] == null) _chains[stackTrace] = _createNode(2);
180 } 162 }
181 163
182 var asyncError = parent.errorCallback(zone, error, stackTrace); 164 var asyncError = parent.errorCallback(zone, error, stackTrace);
183 return asyncError == null ? new AsyncError(error, stackTrace) : asyncError; 165 return asyncError == null ? new AsyncError(error, stackTrace) : asyncError;
184 } 166 }
185 167
186 /// Creates a [_Node] with the current stack trace and linked to 168 /// Creates a [_Node] with the current stack trace and linked to
187 /// [_currentNode]. 169 /// [_currentNode].
188 /// 170 ///
189 /// By default, the first frame of the first trace will be the line where 171 /// By default, the first frame of the first trace will be the line where
190 /// [_createNode] is called. If [level] is passed, the first trace will start 172 /// [_createNode] is called. If [level] is passed, the first trace will start
191 /// that many frames up instead. 173 /// that many frames up instead.
192 _Node _createNode([int level=0]) => 174 _Node _createNode([int level = 0]) =>
193 new _Node(new Trace.current(level + 1), _currentNode); 175 new _Node(_currentTrace(level + 1), _currentNode);
194 176
195 // TODO(nweiz): use a more robust way of detecting and tracking errors when 177 // TODO(nweiz): use a more robust way of detecting and tracking errors when
196 // issue 15105 is fixed. 178 // issue 15105 is fixed.
197 /// Runs [f] with [_currentNode] set to [node]. 179 /// Runs [f] with [_currentNode] set to [node].
198 /// 180 ///
199 /// If [f] throws an error, this associates [node] with that error's stack 181 /// If [f] throws an error, this associates [node] with that error's stack
200 /// trace. 182 /// trace.
201 _run(Function f, _Node node) { 183 _run(Function f, _Node node) {
202 var previousNode = _currentNode; 184 var previousNode = _currentNode;
203 _currentNode = node; 185 _currentNode = node;
(...skipping 10 matching lines...) Expand all
214 196
215 /// A linked list node representing a single entry in a stack chain. 197 /// A linked list node representing a single entry in a stack chain.
216 class _Node { 198 class _Node {
217 /// The stack trace for this link of the chain. 199 /// The stack trace for this link of the chain.
218 final Trace trace; 200 final Trace trace;
219 201
220 /// The previous node in the chain. 202 /// The previous node in the chain.
221 final _Node previous; 203 final _Node previous;
222 204
223 _Node(StackTrace trace, [this.previous]) 205 _Node(StackTrace trace, [this.previous])
224 : trace = trace == null ? new Trace.current() : new Trace.from(trace); 206 : trace = trace == null ? _currentTrace() : new Trace.from(trace);
225 207
226 /// Converts this to a [Chain]. 208 /// Converts this to a [Chain].
227 Chain toChain() { 209 Chain toChain() {
228 var nodes = <Trace>[]; 210 var nodes = <Trace>[];
229 var node = this; 211 var node = this;
230 while (node != null) { 212 while (node != null) {
231 nodes.add(node.trace); 213 nodes.add(node.trace);
232 node = node.previous; 214 node = node.previous;
233 } 215 }
234 return new Chain(nodes); 216 return new Chain(nodes);
235 } 217 }
236 } 218 }
219
220 /// Like [new Trace.current], but if the current stack trace has VM chaining
221 /// enabled, this only returns the innermost sub-trace.
222 Trace _currentTrace([int level]) {
223 level ??= 0;
224 var stackTrace = StackTrace.current;
225 return new LazyTrace(() {
226 // Ignore the VM's stack chains when we generate our own. Otherwise we'll
227 // end up with duplicate frames all over the place.
228 var text = stackTrace.toString();
229 var index = text.indexOf(vmChainGap);
230 if (index != -1) text = text.substring(0, index);
231
232 var trace = new Trace.parse(text);
233 // JS includes a frame for the call to StackTrace.current, but the VM
234 // doesn't, so we skip an extra frame in a JS context.
235 return new Trace(trace.frames.skip(level + (inJS ? 2 : 1)), original: text);
236 });
237 }
OLDNEW
« no previous file with comments | « packages/stack_trace/lib/src/lazy_trace.dart ('k') | packages/stack_trace/lib/src/trace.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698