Add a "when" parameter to Chain.capture().

This makes it easy for users to switch capturing on and off based on
whether they're in a debug or development mode.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//1583483003 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c99f532..fb699c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
-## 1.5.2
+## 1.6.0
+
+* Add a `when` parameter to `Chain.capture()`. This allows capturing to be
+  easily enabled and disabled based on whether the application is running in
+  debug/development mode or not.
 
 * Deprecate the `ChainHandler` typedef. This didn't provide any value over
   directly annotating the function argument, and it made the documentation less
diff --git a/lib/src/chain.dart b/lib/src/chain.dart
index 4baec21..3f35c16 100644
--- a/lib/src/chain.dart
+++ b/lib/src/chain.dart
@@ -49,8 +49,14 @@
   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 [when] is `true`, runs [callback] in a [Zone] in which the current
+  /// stack chain is tracked and automatically associated with (most) errors.
+  ///
+  /// If [when] is `false`, this does not track stack chains. Instead, it's
+  /// identical to [runZoned], except that it wraps any errors in [new
+  /// Chain.forTrace]—which will only wrap the trace unless there's a different
+  /// [Chain.capture] active. This makes it easy for the caller to only capture
+  /// stack chains in debug mode or during development.
   ///
   /// 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
@@ -64,7 +70,19 @@
   /// considered unhandled.
   ///
   /// If [callback] returns a value, it will be returned by [capture] as well.
-  static capture(callback(), {void onError(error, Chain chain)}) {
+  static capture(callback(), {void onError(error, Chain chain),
+      bool when: true}) {
+    if (!when) {
+      var newOnError;
+      if (onError != null) {
+        newOnError = (error, stackTrace) {
+          onError(error, new Chain.forTrace(stackTrace));
+        };
+      }
+
+      return runZoned(callback, onError: newOnError);
+    }
+
     var spec = new StackZoneSpecification(onError);
     return runZoned(() {
       try {
diff --git a/pubspec.yaml b/pubspec.yaml
index 242d305..1c805c3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,7 @@
 #
 # When the major version is upgraded, you *must* update that version constraint
 # in pub to stay in sync with this.
-version: 1.5.2-dev
+version: 1.6.0
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://github.com/dart-lang/stack_trace
 description: >
diff --git a/test/chain/chain_test.dart b/test/chain/chain_test.dart
index cddb4a6..40b06d5 100644
--- a/test/chain/chain_test.dart
+++ b/test/chain/chain_test.dart
@@ -36,6 +36,22 @@
     });
   });
 
+  group("Chain.capture() with when: false", () {
+    test("with no onError doesn't block errors", () {
+      expect(Chain.capture(() => new Future.error("oh no"), when: false),
+          throwsA("oh no"));
+    });
+
+    test("with onError blocks errors", () {
+      Chain.capture(() {
+        return new Future.error("oh no");
+      }, onError: expectAsync((error, chain) {
+        expect(error, equals("oh no"));
+        expect(chain, new isInstanceOf<Chain>());
+      }), when: false);
+    });
+  });
+
   test("toString() ensures that all traces are aligned", () {
     var chain = new Chain([
       new Trace.parse('short 10:11  Foo.bar\n'),