src/debug.js
/*jslint indent:2, node:true, sloppy:true */
var util = require('./util');
/**
* A freedom entry point for debugging.
* @uses handleEvents
* @implements Port
* @constructor
*/
var Debug = function (logger) {
this.id = 'debug';
this.emitChannel = false;
this.config = false;
util.handleEvents(this);
};
/**
* The supported log levels for debugging.
* @static
*/
Debug.LEVELS = ['debug', 'info', 'log', 'warn', 'error'];
/**
* Provide a textual description of this port.
* @method toString
* @return {String} the textual description.
*/
Debug.prototype.toString = function () {
return '[Console]';
};
/**
* Register a logger for outputting debugging messages.
* @method setLogger
* @param {Console} logger The logger to register
*/
Debug.prototype.setLogger = function (logger) {
if (this.logger) {
this.info('Replacing Logger.');
}
this.logger = logger;
this.emit('logger');
};
/**
* Handler for receiving messages sent to the debug port.
* These messages are used to retreive config for exposing console.
* @method onMessage
* @param {String} source the source identifier for the message.
* @param {Object} message the received message.
*/
Debug.prototype.onMessage = function (source, message) {
if (source === 'control' && message.channel && !this.emitChannel) {
this.emitChannel = message.channel;
this.config = message.config;
if (!this.config.global.console) {
if (typeof console !== 'undefined') {
this.config.global.console = console;
} else {
this.config.global.console = this.getLogger('Console');
}
}
this.emit('ready');
}
};
/**
* Dispatch a debug message with arbitrary severity.
* All debug messages are routed through the manager, to allow for delegation.
* @method format
* @param {String} severity the severity of the message.
* @param {String} source The location of message.
* @param {String[]} args The contents of the message.
* @private
*/
Debug.prototype.format = function (severity, source, args) {
var i, alist = [], argarr;
if (typeof args === "string" && source) {
try {
argarr = JSON.parse(args);
if (argarr instanceof Array) {
args = argarr;
}
} catch (e) {
// pass.
}
}
if (typeof args === "string") {
alist.push(args);
} else {
for (i = 0; i < args.length; i += 1) {
alist.push(args[i]);
}
}
if (!this.emitChannel) {
this.on('ready', this.format.bind(this, severity, source, alist));
return;
}
this.emit(this.emitChannel, {
severity: severity,
source: source,
quiet: true,
request: 'debug',
msg: JSON.stringify(alist)
});
};
/**
* Print received messages on the console.
* This is called by the manager in response to an emission from format.
* @method print
* @param {Object} message The message emitted by {@see format} to print.
*/
Debug.prototype.print = function (message) {
if (!this.logger) {
this.once('logger', this.print.bind(this, message));
return;
}
var args, arr = [], i = 0;
args = JSON.parse(message.msg);
if (typeof args === "string") {
arr.push(args);
} else {
while (args[i] !== undefined) {
arr.push(args[i]);
i += 1;
}
}
this.logger[message.severity].call(this.logger, message.source, arr, function () {});
};
/**
* Print a log message to the console.
* @method log
*/
Debug.prototype.log = function () {
this.format('log', undefined, arguments);
};
/**
* Print an info message to the console.
* @method log
*/
Debug.prototype.info = function () {
this.format('info', undefined, arguments);
};
/**
* Print a debug message to the console.
* @method log
*/
Debug.prototype.debug = function () {
this.format('debug', undefined, arguments);
};
/**
* Print a warning message to the console.
* @method warn
*/
Debug.prototype.warn = function () {
this.format('warn', undefined, arguments);
};
/**
* Print an error message to the console.
* @method error
*/
Debug.prototype.error = function () {
this.format('error', undefined, arguments);
};
/**
* Get a logger that logs messages prefixed by a given name.
* @method getLogger
* @param {String} name The prefix for logged messages.
* @returns {Console} A console-like object.
*/
Debug.prototype.getLogger = function (name) {
var log = function (severity, source) {
var args = Array.prototype.splice.call(arguments, 2);
this.format(severity, source, args);
},
logger = {
freedom: true
};
Debug.LEVELS.forEach(function (level) {
logger[level] = log.bind(this, level, name);
}.bind(this));
return logger;
};
/**
* Create a synchronous 'getLogger' method that binds around an asynchronous
* logger by creating a buffer until the asynchronous logger is resolved.
* @see {ModuleInternal.loadLinks} for where this method is bound to the created
* external interface.
* @method getLoggingShim
* @param {Function} asyncMethod The wrapper to 'getLogger'
*/
Debug.prototype.getLoggingShim = function (asyncMethod) {
return function getLogggerSync(name) {
var toResolve = asyncMethod(name),
buffer = [],
methods = Debug.LEVELS,
backing = null,
ret = {};
toResolve.then(function (logger) {
backing = logger;
buffer.forEach(function (item) {
backing[item[0]].apply(backing, item[1]);
});
});
methods.forEach(function (mthd) {
ret[mthd] = function() {
var args = Array.prototype.splice.call(arguments, 0);
if (backing) {
backing[this].apply(backing, args);
} else {
buffer.push([this, args]);
}
}.bind(mthd);
});
return ret;
};
};
module.exports = Debug;