I've attached a patch that adds a logException method to loggers, and a
couple other simple methods. I've included tests, but I've only tested
on Firefox. The names aren't particularly thought out. A better
textForException function would also be nice, especially one that
formatted lines more nicely and gave relative path names for the
Javascript files (I find the full path names a bit tedious).
Index: tests/test_MochiKit-Logging.html
===================================================================
--- tests/test_MochiKit-Logging.html (revision 459)
+++ tests/test_MochiKit-Logging.html (working copy)
@@ -12,7 +12,7 @@
try {
// Counting the number of tests is really lame
- plan({'tests': 27});
+ plan({'tests': 35});
// just in case
logger.clear();
@@ -83,7 +83,43 @@
is( compare(firstTwo, logger.getMessages().slice(0, 2)), 0, "firstTwo" );
+ textForException = MochiKit.Logging.textForException;
+ try {
+ asdf;
+ } catch (e) {
+ msg = textForException(e);
+ ok( msg.indexOf('asdf') >= 0, "contains message");
+ ok( msg.indexOf('ReferenceError') >= 0, "contains exception");
+ ok( msg.indexOf('test_MochiKit-Logging.html') >= 0, "contains filename");
+ }
+
+ function badFunction() {
+ return 1+foo;
+ }
+ failed = false;
+ try {
+ badFunction();
+ } catch (e) {
+ failed = true;
+ msg = textForException(e);
+ ok( msg.indexOf('test_MochiKit-Logging.html') >= 0, "contains filename");
+ /* more? */
+ }
+ ok( failed, "badFunction failed");
+ try {
+ badFunction();
+ } catch (e) {
+ /* Just exercising */
+ logger.logException(e);
+ }
+
+ caughtFunction = MochiKit.Logging.catchException(badFunction);
+ ok( caughtFunction() === false, "catchException");
+ msgs = logger.getMessages();
+ msg = msgs.pop();
+ is( msg.level, "ERROR", "level ERROR");
+ ok( msg.info[0].indexOf('badFunction') >= 0, "logged exception");
// Done!
Index: doc/rst/MochiKit/Logging.rst
===================================================================
--- doc/rst/MochiKit/Logging.rst (revision 459)
+++ doc/rst/MochiKit/Logging.rst (working copy)
@@ -206,7 +206,10 @@
Remove a listener using the ident given to :mochiref:`Logger.prototype.addListener`
+:mochidef:`Logger.prototype.logException(exc)`:
+ Log the exception at level ERROR
+
Functions
---------
@@ -240,7 +243,18 @@
Log a WARNING message to the default logger
+:mochidef:`logException(exc)`:
+ Log the exception at level ERROR
+
+:mochidef:`textForException(exc)`:
+
+ Format the exception as a string
+
+:mochidef:`catchException(func)`:
+
+ Return a wrapped version of the function; if the function raises any exception, log that exception and return ``false``. The return value is helpful when wrapping an event handler, e.g., ``<button onclick="return catchException(func)(...)">`` will always suppress the button submit
+
See Also
========
Index: MochiKit/Logging.js
===================================================================
--- MochiKit/Logging.js (revision 459)
+++ MochiKit/Logging.js (working copy)
@@ -49,14 +49,16 @@
"logError",
"logDebug",
"logFatal",
- "logWarning"
+ "logWarning",
+ "logException"
];
MochiKit.Logging.EXPORT_OK = [
"logLevelAtLeast",
"isLogMessage",
- "compareLogMessage"
+ "compareLogMessage",
+ "textForException"
];
@@ -125,6 +127,33 @@
"\nlevel: " + msg.level +
"\ninfo: " + msg.info.join(" ")
);
+ },
+
+ textForException: function (exc) {
+ var s = exc.name + ': ' + exc.message + '\n';
+ s += exc.stack;
+ return s;
+ for (var i=0; i<exc.stack.length; i++) {
+ var frame = exc.stack[i];
+ s += frame + '\n';
+ }
+ return s;
+ },
+
+ catchException: function (func, /* optional */logger) {
+ function replacement() {
+ try {
+ return func.apply(this, arguments);
+ } catch (e) {
+ if (logger) {
+ logger.logException(e);
+ } else {
+ MochiKit.Logging.logException(e);
+ }
+ return false;
+ }
+ }
+ return replacement;
}
});
@@ -321,6 +350,10 @@
} else {
MochiKit.LoggingPane.createLoggingPane(inline || false);
}
+ },
+
+ logException: function (exc) {
+ this.error(MochiKit.Logging.textForException(exc));
}
};
@@ -365,6 +398,7 @@
this.logDebug = connectLog('debug');
this.logFatal = connectLog('fatal');
this.logWarning = connectLog('warning');
+ this.logException = connectLog('logException');
this.logger = new Logger();
this.EXPORT_TAGS = {