Index: stack_trace/lib/src/chain.dart |
diff --git a/stack_trace/lib/src/chain.dart b/stack_trace/lib/src/chain.dart |
deleted file mode 100644 |
index acd17e9d59ea516498fc50ed89b0ecea07290658..0000000000000000000000000000000000000000 |
--- a/stack_trace/lib/src/chain.dart |
+++ /dev/null |
@@ -1,196 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library stack_trace.chain; |
- |
-import 'dart:async'; |
-import 'dart:collection'; |
-import 'dart:math' as math; |
- |
-import 'frame.dart'; |
-import 'stack_zone_specification.dart'; |
-import 'trace.dart'; |
-import 'utils.dart'; |
- |
-/// A function that handles errors in the zone wrapped by [Chain.capture]. |
-typedef void ChainHandler(error, Chain chain); |
- |
-/// The line used in the string representation of stack chains to represent |
-/// the gap between traces. |
-const _gap = '===== asynchronous gap ===========================\n'; |
- |
-/// A chain of stack traces. |
-/// |
-/// A stack chain is a collection of one or more stack traces that collectively |
-/// represent the path from [main] through nested function calls to a particular |
-/// code location, usually where an error was thrown. Multiple stack traces are |
-/// necessary when using asynchronous functions, since the program's stack is |
-/// reset before each asynchronous callback is run. |
-/// |
-/// Stack chains can be automatically tracked using [Chain.capture]. This sets |
-/// up a new [Zone] in which the current stack chain is tracked and can be |
-/// accessed using [new Chain.current]. Any errors that would be top-leveled in |
-/// the zone can be handled, along with their associated chains, with the |
-/// `onError` callback. For example: |
-/// |
-/// Chain.capture(() { |
-/// // ... |
-/// }, onError: (error, stackChain) { |
-/// print("Caught error $error\n" |
-/// "$stackChain"); |
-/// }); |
-class Chain implements StackTrace { |
- |
- /// The stack traces that make up this chain. |
- /// |
- /// Like the frames in a stack trace, the traces are ordered from most local |
- /// to least local. The first one is the trace where the actual exception was |
- /// raised, the second one is where that callback was scheduled, and so on. |
- final List<Trace> traces; |
- |
- /// The [StackZoneSpecification] for the current zone. |
- static StackZoneSpecification get _currentSpec => |
- Zone.current[#stack_trace.stack_zone.spec]; |
- |
- /// Runs [callback] in a [Zone] in which the current stack chain is tracked |
- /// and automatically associated with (most) errors. |
- /// |
- /// If [onError] is passed, any error in the zone that would otherwise go |
- /// unhandled is passed to it, along with the [Chain] associated with that |
- /// error. Note that if [callback] produces multiple unhandled errors, |
- /// [onError] may be called more than once. If [onError] isn't passed, the |
- /// parent Zone's `unhandledErrorHandler` will be called with the error and |
- /// its chain. |
- /// |
- /// Note that even if [onError] isn't passed, this zone will still be an error |
- /// zone. This means that any errors that would cross the zone boundary are |
- /// considered unhandled. |
- /// |
- /// If [callback] returns a value, it will be returned by [capture] as well. |
- static capture(callback(), {ChainHandler onError}) { |
- var spec = new StackZoneSpecification(onError); |
- return runZoned(() { |
- try { |
- return callback(); |
- } catch (error, stackTrace) { |
- // TODO(nweiz): Don't special-case this when issue 19566 is fixed. |
- return Zone.current.handleUncaughtError(error, stackTrace); |
- } |
- }, zoneSpecification: spec.toSpec(), zoneValues: { |
- #stack_trace.stack_zone.spec: spec |
- }); |
- } |
- |
- /// Returns [futureOrStream] unmodified. |
- /// |
- /// Prior to Dart 1.7, this was necessary to ensure that stack traces for |
- /// exceptions reported with [Completer.completeError] and |
- /// [StreamController.addError] were tracked correctly. |
- @Deprecated("Chain.track is not necessary in Dart 1.7+.") |
- static track(futureOrStream) => futureOrStream; |
- |
- /// Returns the current stack chain. |
- /// |
- /// By default, the first frame of the first trace will be the line where |
- /// [Chain.current] is called. If [level] is passed, the first trace will |
- /// start that many frames up instead. |
- /// |
- /// If this is called outside of a [capture] zone, it just returns a |
- /// single-trace chain. |
- factory Chain.current([int level=0]) { |
- if (_currentSpec != null) return _currentSpec.currentChain(level + 1); |
- return new Chain([new Trace.current(level + 1)]); |
- } |
- |
- /// Returns the stack chain associated with [trace]. |
- /// |
- /// The first stack trace in the returned chain will always be [trace] |
- /// (converted to a [Trace] if necessary). If there is no chain associated |
- /// with [trace] or if this is called outside of a [capture] zone, this just |
- /// returns a single-trace chain containing [trace]. |
- /// |
- /// If [trace] is already a [Chain], it will be returned as-is. |
- factory Chain.forTrace(StackTrace trace) { |
- if (trace is Chain) return trace; |
- if (_currentSpec == null) return new Chain([new Trace.from(trace)]); |
- return _currentSpec.chainFor(trace); |
- } |
- |
- /// Parses a string representation of a stack chain. |
- /// |
- /// Specifically, this parses the output of [Chain.toString]. |
- factory Chain.parse(String chain) { |
- if (chain.isEmpty) return new Chain([]); |
- return new Chain( |
- chain.split(_gap).map((trace) => new Trace.parseFriendly(trace))); |
- } |
- |
- /// Returns a new [Chain] comprised of [traces]. |
- Chain(Iterable<Trace> traces) |
- : traces = new UnmodifiableListView<Trace>(traces.toList()); |
- |
- /// Returns a terser version of [this]. |
- /// |
- /// This calls [Trace.terse] on every trace in [traces], and discards any |
- /// trace that contain only internal frames. |
- Chain get terse => foldFrames((_) => false, terse: true); |
- |
- /// Returns a new [Chain] based on [this] where multiple stack frames matching |
- /// [predicate] are folded together. |
- /// |
- /// This means that whenever there are multiple frames in a row that match |
- /// [predicate], only the last one is kept. In addition, traces that are |
- /// composed entirely of frames matching [predicate] are omitted. |
- /// |
- /// This is useful for limiting the amount of library code that appears in a |
- /// stack trace by only showing user code and code that's called by user code. |
- /// |
- /// If [terse] is true, this will also fold together frames from the core |
- /// library or from this package, and simplify core library frames as in |
- /// [Trace.terse]. |
- Chain foldFrames(bool predicate(Frame frame), {bool terse: false}) { |
- var foldedTraces = traces.map( |
- (trace) => trace.foldFrames(predicate, terse: terse)); |
- var nonEmptyTraces = foldedTraces.where((trace) { |
- // Ignore traces that contain only folded frames. |
- if (trace.frames.length > 1) return true; |
- |
- // In terse mode, the trace may have removed an outer folded frame, |
- // leaving a single non-folded frame. We can detect a folded frame because |
- // it has no line information. |
- if (!terse) return false; |
- return trace.frames.single.line != null; |
- }); |
- |
- // If all the traces contain only internal processing, preserve the last |
- // (top-most) one so that the chain isn't empty. |
- if (nonEmptyTraces.isEmpty && foldedTraces.isNotEmpty) { |
- return new Chain([foldedTraces.last]); |
- } |
- |
- return new Chain(nonEmptyTraces); |
- } |
- |
- /// Converts [this] to a [Trace]. |
- /// |
- /// The trace version of a chain is just the concatenation of all the traces |
- /// in the chain. |
- Trace toTrace() => new Trace(flatten(traces.map((trace) => trace.frames))); |
- |
- String toString() { |
- // Figure out the longest path so we know how much to pad. |
- var longest = traces.map((trace) { |
- return trace.frames.map((frame) => frame.location.length) |
- .fold(0, math.max); |
- }).fold(0, math.max); |
- |
- // Don't call out to [Trace.toString] here because that doesn't ensure that |
- // padding is consistent across all traces. |
- return traces.map((trace) { |
- return trace.frames.map((frame) { |
- return '${padRight(frame.location, longest)} ${frame.member}\n'; |
- }).join(); |
- }).join(_gap); |
- } |
-} |