add logging support for exceptions

BUG=
R=gram@google.com

Review URL: https://codereview.chromium.org//17467008

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/logging@24246 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/logging.dart b/lib/logging.dart
index b29f076..3c841dc 100644
--- a/lib/logging.dart
+++ b/lib/logging.dart
@@ -153,10 +153,9 @@
    * [Level.INFO], [Level.WARNING], etc) you can use their specialized methods
    * instead (e.g. [info], [warning], etc).
    */
-  // TODO(sigmund): add support for logging exceptions.
-  void log(Level logLevel, String message) {
+  void log(Level logLevel, String message, [exception]) {
     if (isLoggable(logLevel)) {
-      var record = new LogRecord(logLevel, message, fullName);
+      var record = new LogRecord(logLevel, message, fullName, exception);
       if (hierarchicalLoggingEnabled) {
         var target = this;
         while (target != null) {
@@ -170,28 +169,36 @@
   }
 
   /** Log message at level [Level.FINEST]. */
-  void finest(String message) => log(Level.FINEST, message);
+  void finest(String message, [exception]) =>
+      log(Level.FINEST, message, exception);
 
   /** Log message at level [Level.FINER]. */
-  void finer(String message) => log(Level.FINER, message);
+  void finer(String message, [exception]) =>
+      log(Level.FINER, message, exception);
 
   /** Log message at level [Level.FINE]. */
-  void fine(String message) => log(Level.FINE, message);
+  void fine(String message, [exception]) =>
+      log(Level.FINE, message, exception);
 
   /** Log message at level [Level.CONFIG]. */
-  void config(String message) => log(Level.CONFIG, message);
+  void config(String message, [exception]) =>
+      log(Level.CONFIG, message, exception);
 
   /** Log message at level [Level.INFO]. */
-  void info(String message) => log(Level.INFO, message);
+  void info(String message, [exception]) =>
+      log(Level.INFO, message, exception);
 
   /** Log message at level [Level.WARNING]. */
-  void warning(String message) => log(Level.WARNING, message);
+  void warning(String message, [exception]) =>
+      log(Level.WARNING, message, exception);
 
   /** Log message at level [Level.SEVERE]. */
-  void severe(String message) => log(Level.SEVERE, message);
+  void severe(String message, [exception]) =>
+      log(Level.SEVERE, message, exception);
 
   /** Log message at level [Level.SHOUT]. */
-  void shout(String message) => log(Level.SHOUT, message);
+  void shout(String message, [exception]) =>
+      log(Level.SHOUT, message, exception);
 
   Stream<LogRecord> _getStream() {
     if (hierarchicalLoggingEnabled || parent == null) {
@@ -308,14 +315,9 @@
   static int _nextNumber = 0;
 
   /** Associated exception (if any) when recording errors messages. */
-  Exception exception;
+  var exception;
 
-  /** Associated exception message (if any) when recording errors messages. */
-  String exceptionText;
-
-  LogRecord(
-      this.level, this.message, this.loggerName,
-      [time, this.exception, this.exceptionText]) :
-    this.time = (time == null) ? new DateTime.now() : time,
-    this.sequenceNumber = LogRecord._nextNumber++;
+  LogRecord(this.level, this.message, this.loggerName, [this.exception])
+      : time = new DateTime.now(),
+        sequenceNumber = LogRecord._nextNumber++;
 }
diff --git a/test/logging_test.dart b/test/logging_test.dart
index 1af342f..a631e8c 100644
--- a/test/logging_test.dart
+++ b/test/logging_test.dart
@@ -228,6 +228,49 @@
         'SHOUT: 8']));
     });
 
+    test('logging methods store exception', () {
+      root.level = Level.ALL;
+      var rootMessages = [];
+      root.onRecord.listen((r) {
+        rootMessages.add('${r.level}: ${r.message} ${r.exception}');
+      });
+
+      root.finest('1');
+      root.finer('2');
+      root.fine('3');
+      root.config('4');
+      root.info('5');
+      root.warning('6');
+      root.severe('7');
+      root.shout('8');
+      root.finest('1', 'a');
+      root.finer('2', 'b');
+      root.fine('3', ['c']);
+      root.config('4', 'd');
+      root.info('5', 'e');
+      root.warning('6', 'f');
+      root.severe('7', 'g');
+      root.shout('8', 'h');
+
+      expect(rootMessages, equals([
+        'FINEST: 1 null',
+        'FINER: 2 null',
+        'FINE: 3 null',
+        'CONFIG: 4 null',
+        'INFO: 5 null',
+        'WARNING: 6 null',
+        'SEVERE: 7 null',
+        'SHOUT: 8 null',
+        'FINEST: 1 a',
+        'FINER: 2 b',
+        'FINE: 3 [c]',
+        'CONFIG: 4 d',
+        'INFO: 5 e',
+        'WARNING: 6 f',
+        'SEVERE: 7 g',
+        'SHOUT: 8 h']));
+    });
+
     test('message logging - no hierarchy', () {
       root.level = Level.WARNING;
       var rootMessages = [];