Add option to automatically record stack trace in logging (fixes #2)
R=jmesserly@google.com
Review URL: https://codereview.chromium.org//1132533003
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d072302..b0b759e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.11.1
+
+* Add support for automatically logging the stack trace on error messages. Note
+ this can be expensive, so it is off by default.
+
## 0.11.0
* Revert change in `0.10.0`. `stackTrace` must be an instance of `StackTrace`.
diff --git a/lib/logging.dart b/lib/logging.dart
index 7654885..f108ed3 100644
--- a/lib/logging.dart
+++ b/lib/logging.dart
@@ -16,6 +16,12 @@
bool hierarchicalLoggingEnabled = false;
/**
+ * Automatically record stack traces for any message of this level or above.
+ * Because this is expensive, this is off by default.
+ */
+Level recordStackTraceAtLevel = Level.OFF;
+
+/**
* Level for the root-logger. This will be the level of all loggers if
* [hierarchicalLoggingEnabled] is false.
*/
@@ -147,11 +153,15 @@
void log(Level logLevel, message,
[Object error, StackTrace stackTrace, Zone zone]) {
if (isLoggable(logLevel)) {
- // If message is a Function, evaluate it.
if (message is Function) message = message();
- // If message is still not a String, call toString().
if (message is! String) message = message.toString();
- // Only record the current zone if it was not given.
+ if (stackTrace == null && logLevel >= recordStackTraceAtLevel) {
+ try {
+ throw "autogenerated stack trace for $logLevel $message";
+ } catch (e, t) {
+ stackTrace = t;
+ }
+ }
if (zone == null) zone = Zone.current;
var record =
diff --git a/pubspec.yaml b/pubspec.yaml
index 2b7d130..1236b30 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: logging
-version: 0.11.0
+version: 0.11.1
author: Dart Team <misc@dartlang.org>
description: >
Provides APIs for debugging and error logging. This library introduces
diff --git a/test/logging_test.dart b/test/logging_test.dart
index 94696d8..e27ee2f 100644
--- a/test/logging_test.dart
+++ b/test/logging_test.dart
@@ -520,4 +520,54 @@
equals(['INFO: 5', 'INFO: false', 'INFO: [1, 2, 3]', 'INFO: 10',]));
});
});
+
+ group('recordStackTraceAtLevel', () {
+ var root = Logger.root;
+ tearDown(() {
+ recordStackTraceAtLevel = Level.OFF;
+ root.clearListeners();
+ });
+
+ test('no stack trace by default', () {
+ var records = new List<LogRecord>();
+ root.onRecord.listen(records.add);
+ root.severe('hello');
+ root.warning('hello');
+ root.info('hello');
+ expect(records, hasLength(3));
+ expect(records[0].stackTrace, isNull);
+ expect(records[1].stackTrace, isNull);
+ expect(records[2].stackTrace, isNull);
+ });
+
+ test('trace recorded only on requested levels', () {
+ var records = new List<LogRecord>();
+ recordStackTraceAtLevel = Level.WARNING;
+ root.onRecord.listen(records.add);
+ root.severe('hello');
+ root.warning('hello');
+ root.info('hello');
+ expect(records, hasLength(3));
+ expect(records[0].stackTrace, isNotNull);
+ expect(records[1].stackTrace, isNotNull);
+ expect(records[2].stackTrace, isNull);
+ });
+
+ test('provided trace is used if given', () {
+ var trace;
+ try {
+ throw 'trace';
+ } catch(e, t) {
+ trace = t;
+ }
+ var records = new List<LogRecord>();
+ recordStackTraceAtLevel = Level.WARNING;
+ root.onRecord.listen(records.add);
+ root.severe('hello');
+ root.warning('hello', 'a', trace);
+ expect(records, hasLength(2));
+ expect(records[0].stackTrace, isNot(equals(trace)));
+ expect(records[1].stackTrace, trace);
+ });
+ });
}