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

Side by Side Diff: observatory_pub_packages/stack_trace/src/chain.dart

Issue 816693004: Add observatory_pub_packages snapshot to third_party (Closed) Base URL: http://dart.googlecode.com/svn/third_party/
Patch Set: Created 6 years 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library stack_trace.chain;
6
7 import 'dart:async';
8 import 'dart:collection';
9
10 import 'frame.dart';
11 import 'stack_zone_specification.dart';
12 import 'trace.dart';
13 import 'utils.dart';
14
15 /// A function that handles errors in the zone wrapped by [Chain.capture].
16 typedef void ChainHandler(error, Chain chain);
17
18 /// A chain of stack traces.
19 ///
20 /// A stack chain is a collection of one or more stack traces that collectively
21 /// represent the path from [main] through nested function calls to a particular
22 /// code location, usually where an error was thrown. Multiple stack traces are
23 /// necessary when using asynchronous functions, since the program's stack is
24 /// reset before each asynchronous callback is run.
25 ///
26 /// Stack chains can be automatically tracked using [Chain.capture]. This sets
27 /// up a new [Zone] in which the current stack chain is tracked and can be
28 /// accessed using [new Chain.current]. Any errors that would be top-leveled in
29 /// the zone can be handled, along with their associated chains, with the
30 /// `onError` callback. For example:
31 ///
32 /// Chain.capture(() {
33 /// // ...
34 /// }, onError: (error, stackChain) {
35 /// print("Caught error $error\n"
36 /// "$stackChain");
37 /// });
38 class Chain implements StackTrace {
39 /// The line used in the string representation of stack chains to represent
40 /// the gap between traces.
41 static const _GAP = '===== asynchronous gap ===========================\n';
42
43 /// The stack traces that make up this chain.
44 ///
45 /// Like the frames in a stack trace, the traces are ordered from most local
46 /// to least local. The first one is the trace where the actual exception was
47 /// raised, the second one is where that callback was scheduled, and so on.
48 final List<Trace> traces;
49
50 /// The [StackZoneSpecification] for the current zone.
51 static StackZoneSpecification get _currentSpec =>
52 Zone.current[#stack_trace.stack_zone.spec];
53
54 /// Runs [callback] in a [Zone] in which the current stack chain is tracked
55 /// and automatically associated with (most) errors.
56 ///
57 /// If [onError] is passed, any error in the zone that would otherwise go
58 /// unhandled is passed to it, along with the [Chain] associated with that
59 /// error. Note that if [callback] produces multiple unhandled errors,
60 /// [onError] may be called more than once. If [onError] isn't passed, the
61 /// parent Zone's `unhandledErrorHandler` will be called with the error and
62 /// its chain.
63 ///
64 /// Note that even if [onError] isn't passed, this zone will still be an error
65 /// zone. This means that any errors that would cross the zone boundary are
66 /// considered unhandled.
67 ///
68 /// If [callback] returns a value, it will be returned by [capture] as well.
69 ///
70 /// Currently, capturing stack chains doesn't work when using dart2js due to
71 /// issues [15171] and [15105]. Stack chains reported on dart2js will contain
72 /// only one trace.
73 ///
74 /// [15171]: https://code.google.com/p/dart/issues/detail?id=15171
75 /// [15105]: https://code.google.com/p/dart/issues/detail?id=15105
76 static capture(callback(), {ChainHandler onError}) {
77 var spec = new StackZoneSpecification(onError);
78 return runZoned(() {
79 try {
80 return callback();
81 } catch (error, stackTrace) {
82 // TODO(nweiz): Don't special-case this when issue 19566 is fixed.
83 return Zone.current.handleUncaughtError(error, stackTrace);
84 }
85 }, zoneSpecification: spec.toSpec(), zoneValues: {
86 #stack_trace.stack_zone.spec: spec
87 });
88 }
89
90 /// Returns [futureOrStream] unmodified.
91 ///
92 /// Prior to Dart 1.7, this was necessary to ensure that stack traces for
93 /// exceptions reported with [Completer.completeError] and
94 /// [StreamController.addError] were tracked correctly.
95 @Deprecated("Chain.track is not necessary in Dart 1.7+.")
96 static track(futureOrStream) => futureOrStream;
97
98 /// Returns the current stack chain.
99 ///
100 /// By default, the first frame of the first trace will be the line where
101 /// [Chain.current] is called. If [level] is passed, the first trace will
102 /// start that many frames up instead.
103 ///
104 /// If this is called outside of a [capture] zone, it just returns a
105 /// single-trace chain.
106 factory Chain.current([int level=0]) {
107 if (_currentSpec != null) return _currentSpec.currentChain(level + 1);
108 return new Chain([new Trace.current(level + 1)]);
109 }
110
111 /// Returns the stack chain associated with [trace].
112 ///
113 /// The first stack trace in the returned chain will always be [trace]
114 /// (converted to a [Trace] if necessary). If there is no chain associated
115 /// with [trace] or if this is called outside of a [capture] zone, this just
116 /// returns a single-trace chain containing [trace].
117 ///
118 /// If [trace] is already a [Chain], it will be returned as-is.
119 factory Chain.forTrace(StackTrace trace) {
120 if (trace is Chain) return trace;
121 if (_currentSpec == null) return new Chain([new Trace.from(trace)]);
122 return _currentSpec.chainFor(trace);
123 }
124
125 /// Parses a string representation of a stack chain.
126 ///
127 /// Specifically, this parses the output of [Chain.toString].
128 factory Chain.parse(String chain) =>
129 new Chain(chain.split(_GAP).map((trace) => new Trace.parseFriendly(trace)));
130
131 /// Returns a new [Chain] comprised of [traces].
132 Chain(Iterable<Trace> traces)
133 : traces = new UnmodifiableListView<Trace>(traces.toList());
134
135 /// Returns a terser version of [this].
136 ///
137 /// This calls [Trace.terse] on every trace in [traces], and discards any
138 /// trace that contain only internal frames.
139 Chain get terse {
140 var terseTraces = traces.map((trace) => trace.terse);
141 var nonEmptyTraces = terseTraces.where((trace) {
142 // Ignore traces that contain only internal processing.
143 return trace.frames.length > 1;
144 });
145
146 // If all the traces contain only internal processing, preserve the last
147 // (top-most) one so that the chain isn't empty.
148 if (nonEmptyTraces.isEmpty && terseTraces.isNotEmpty) {
149 return new Chain([terseTraces.last]);
150 }
151
152 return new Chain(nonEmptyTraces);
153 }
154
155 /// Returns a new [Chain] based on [this] where multiple stack frames matching
156 /// [predicate] are folded together.
157 ///
158 /// This means that whenever there are multiple frames in a row that match
159 /// [predicate], only the last one is kept. In addition, traces that are
160 /// composed entirely of frames matching [predicate] are omitted.
161 ///
162 /// This is useful for limiting the amount of library code that appears in a
163 /// stack trace by only showing user code and code that's called by user code.
164 Chain foldFrames(bool predicate(Frame frame)) {
165 var foldedTraces = traces.map((trace) => trace.foldFrames(predicate));
166 var nonEmptyTraces = foldedTraces.where((trace) {
167 // Ignore traces that contain only folded frames. These traces will be
168 // folded into a single frame each.
169 return trace.frames.length > 1;
170 });
171
172 // If all the traces contain only internal processing, preserve the last
173 // (top-most) one so that the chain isn't empty.
174 if (nonEmptyTraces.isEmpty && foldedTraces.isNotEmpty) {
175 return new Chain([foldedTraces.last]);
176 }
177
178 return new Chain(nonEmptyTraces);
179 }
180
181 /// Converts [this] to a [Trace].
182 ///
183 /// The trace version of a chain is just the concatenation of all the traces
184 /// in the chain.
185 Trace toTrace() => new Trace(flatten(traces.map((trace) => trace.frames)));
186
187 String toString() => traces.join(_GAP);
188 }
OLDNEW
« no previous file with comments | « observatory_pub_packages/source_span/src/utils.dart ('k') | observatory_pub_packages/stack_trace/src/frame.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698