| Index: lib/logger.js |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/lib/logger.js |
| @@ -0,0 +1,142 @@ |
| +/** |
| + * Logging service. This is not the log function itself, but rather provide a factory for making such. |
| + * |
| + * @param {String} module |
| + * The name identifying the main module. |
| + * @constructor |
| + */ |
| +var Logger = function( module ) |
| +{ |
| + /** |
| + * The module name |
| + * @type {String} |
| + */ |
| + this.module = module; |
| + |
| + /** |
| + * Global flag to suppress all output. |
| + * @type {boolean} |
| + * @private |
| + */ |
| + this._suppressed = false; |
| + |
| + /** |
| + * The console service used to report messages. This instance is used to get access to logMessage, which |
| + * we use as a static function. |
| + */ |
| + this.console_service = |
| + Components.classes["@mozilla.org/consoleservice;1"].getService( Components.interfaces.nsIConsoleService ); |
| +}; |
| +exports.Logger = Logger; |
| + |
| +Logger.prototype.suppress = function( suppressed ) |
| +{ |
| + this._suppressed = suppressed; |
| +}; |
| + |
| +/** |
| + * Create an ordinary log function with a consistent naming convention. |
| + * |
| + * @param {String} [submodule] |
| + * The name identifying some piece of the main module. |
| + * @return {Function} |
| + * A two-argument function with the ordinary signature for a log message. |
| + */ |
| +Logger.prototype.make_log = function( submodule ) |
| +{ |
| + var prefix = this.module; |
| + if ( submodule && submodule.length > 0 ) |
| + { |
| + prefix += "/" + submodule; |
| + } |
| + prefix += ": "; |
| + return this.log.bind( this, prefix ); |
| +}; |
| + |
| +/** |
| + * Display a log message whose location is reported as the source line of the caller, rather than some line within |
| + * the log function itself. |
| + * <p/> |
| + * Note that this function would ordinarily be called from a function returned from make_log(), which computes the |
| + * prefix argument. This is not a hard requirement, but rather a recommended practice. |
| + * |
| + * @param {String} prefix |
| + * String to be prepended before the message argument. |
| + * @param {String} message |
| + * The main error message. |
| + * @param {Boolean} [allow] |
| + * If present and false, suppresses the message. Allows disabling a log message by arbitrary category, |
| + * as implemented by the caller. |
| + */ |
| +Logger.prototype.log = function( prefix, message, allow ) |
| +{ |
| + if ( ( arguments.length >= 3 && !allow ) || this._suppressed ) |
| + { |
| + // Assert we have an explicit argument to disallow the message |
| + return; |
| + } |
| + var error_report = |
| + Components.classes["@mozilla.org/scripterror;1"].createInstance( Components.interfaces.nsIScriptError ); |
| + var caller = Components.stack.caller; |
| + |
| + /* |
| + * Remove the beginning of any filename value that contains a text arrow. This notation is used to indicate the |
| + * complete link path by which the source came into context. While complete, it makes the links presented in |
| + * the error console non-clickable. |
| + */ |
| + var filename = caller.filename; |
| + var n = filename.lastIndexOf( " -> " ); |
| + if ( n > -1 ) |
| + { |
| + filename = filename.substr( n + 4 ); |
| + } |
| + |
| + error_report.init( prefix + message, filename, null, caller.lineNumber, null, 1, "javascript" ); |
| + this.console_service.logMessage( error_report ); |
| + |
| + /* |
| + * This line was used during development to see just what was in the scripterror object. Unfortunately, making a |
| + * string message that exactly matches this format does not display as an error. In particular there is no |
| + * clickable link displayed. Thus the best we can do is to display a warning with a link, rather than an ordinary |
| + * console message, which doesn't display a clickable location. |
| + */ |
| + //Cu.reportError( "ScriptError=" + scriptError.toString() ); |
| +}; |
| + |
| +/** |
| + * Emit a stack trace to the log. |
| + */ |
| +Logger.prototype.stack_trace = function() |
| +{ |
| + var e = new Error(); |
| + this.log( "", e.stack ); |
| +}; |
| + |
| + |
| +function pad2( n ) |
| +{ |
| + var s = String( n ); |
| + if ( n < 10 ) |
| + s = "0" + s; |
| + return s; |
| +} |
| + |
| +function pad3( n ) |
| +{ |
| + var s = String( n ); |
| + if ( n < 100 ) |
| + { |
| + s = "0" + s; |
| + if ( n < 10 ) |
| + s = "0" + s; |
| + } |
| + return s; |
| +} |
| + |
| +Logger.timestamp = function() |
| +{ |
| + let date = new Date(); |
| + return date.getUTCFullYear() + "-" + pad2( date.getUTCMonth() + 1 ) + "-" + pad2( date.getUTCDate() ) |
| + + " " + pad2( date.getUTCHours() ) + ":" + pad2( date.getUTCMinutes() ) + ":" + pad2( date.getUTCSeconds() ) |
| + + "." + pad3( date.getUTCMilliseconds() ); |
| +}; |