Log: New logging system.

Right now, all I've done is move the logging function from utils to its own
file. I've also refactored it and created some classes.

Next step would be to somehow get rid of the trace setting. The Remote class
should have nothing to do with logging settings. Perhaps we can keep the setting
for backwards compatibility only, but the main way to turn logging on/off or
filter logging messages should be through the Log class.
This commit is contained in:
Stefan Thomas
2014-02-27 23:38:31 -08:00
parent 44dd0ca4a3
commit a003d261ea
6 changed files with 160 additions and 44 deletions

116
src/js/ripple/log.js Normal file
View File

@@ -0,0 +1,116 @@
/**
* Logging functionality for ripple-lib and any applications built on it.
*/
var Log = function (namespace) {
if (!namespace) {
this._namespace = [];
} else if (Array.isArray(namespace)) {
this._namespace = namespace;
} else {
this._namespace = [""+namespace];
}
this._prefix = this._namespace.concat(['']).join(': ');
};
/**
* Create a sub-logger.
*
* You can have a hierarchy of loggers.
*
* @example
*
* var log = require('ripple').log.sub('server');
*
* log.info('connection successful');
* // prints: "server: connection successful"
*/
Log.prototype.sub = function (namespace) {
var subNamespace = this._namespace.slice();
if (namespace && "string" === typeof namespace) subNamespace.push(namespace);
var subLogger = new Log(subNamespace);
subLogger._setParent(this);
return subLogger;
};
Log.prototype._setParent = function (parentLogger) {
this._parent = parentLogger;
};
Log.makeLevel = function (level) {
return function () {
arguments[0] = this._prefix + arguments[0];
Log.engine.logObject.apply(Log, Array.prototype.slice.call(arguments));
};
};
Log.prototype.debug = Log.makeLevel(1);
Log.prototype.info = Log.makeLevel(2);
Log.prototype.warn = Log.makeLevel(3);
Log.prototype.error = Log.makeLevel(4);
/**
* Basic logging connector.
*
* This engine has no formatting and works with the most basic of "console.log"
* implementations. This is the logging engine used in Node.js.
*/
var BasicLogEngine = {
logObject: function logObject(msg) {
var args = Array.prototype.slice.call(arguments, 1);
args = args.map(function(arg) {
return JSON.stringify(arg, null, 2);
});
args.unshift(msg);
console.log.apply(console, args);
}
};
/**
* Null logging connector.
*
* This engine simply swallows all messages. Used when console.log is not
* available.
*/
var NullLogEngine = {
logObject: function () {}
};
Log.engine = NullLogEngine;
if (console && console.log) Log.engine = BasicLogEngine;
/**
* Provide a root logger as our main export.
*
* This means you can use the logger easily on the fly:
* ripple.log.debug('My object is', myObj);
*/
module.exports = new Log();
/**
* This is the logger for ripple-lib internally.
*/
module.exports.internal = module.exports.sub();
/**
* Expose the class as well.
*/
module.exports.Log = Log;
/**
* An easy way to create a new logger for a namespace.
*
* Browser:
* var log = ripple.log.called('client.id');
* log.debug('My object is', myObj);
*
* Node.js:
* var log = require('ripple').log.called('gateway.main');
* log.debug('My object is', myObj);
*/
module.exports.called = Log.makeLogger;

30
src/js/ripple/log.web.js Normal file
View File

@@ -0,0 +1,30 @@
var exports = module.exports = require('./log.js');
/**
* Log engine for browser consoles.
*
* Browsers tend to have better consoles that support nicely formatted
* JavaScript objects. This connector passes objects through to the logging
* function without any stringification.
*/
var InteractiveLogEngine = {
logObject: function (msg, obj) {
var args = Array.prototype.slice.call(arguments, 1);
args = args.map(function(arg) {
if (/MSIE/.test(navigator.userAgent)) {
return JSON.stringify(arg, null, 2);
} else {
return arg;
}
});
args.unshift(msg);
console.log.apply(console, args);
}
};
if (window.console && window.console.log) {
exports.Log.engine = InteractiveLogEngine;
}

View File

@@ -30,6 +30,7 @@ var RippleError = require('./rippleerror').RippleError;
var utils = require('./utils');
var sjcl = require('./utils').sjcl;
var config = require('./config');
var log = require('./log').internal.sub('remote');
/**
Interface to manage the connection to a Ripple server.
@@ -358,7 +359,7 @@ Remote.prototype.setSecret = function(account, secret) {
Remote.prototype._trace = function() {
if (this.trace) {
utils.logObject.apply(utils, arguments);
log.info.apply(log, arguments);
}
};

View File

@@ -3,6 +3,7 @@ var EventEmitter = require('events').EventEmitter;
var Transaction = require('./transaction').Transaction;
var Amount = require('./amount').Amount;
var utils = require('./utils');
var log = require('./log').internal.sub('server');
/**
* @constructor Server
@@ -104,7 +105,7 @@ Server.onlineStates = [
Server.prototype._setState = function(state) {
if (state !== this._state) {
this._remote._trace('server: set_state:', state);
this._remote.trace && log.info('set_state:', state);
this._state = state;
this.emit('state', state);
@@ -189,7 +190,7 @@ Server.prototype.connect = function() {
// we will automatically reconnect.
if (this._connected) return;
this._remote._trace('server: connect:', this._opts.url);
this._remote.trace && log.info('connect:', this._opts.url);
// Ensure any existing socket is given the command to close first.
if (this._ws) this._ws.close();
@@ -223,7 +224,7 @@ Server.prototype.connect = function() {
// If we are no longer the active socket, simply ignore any event
if (ws === self._ws) {
self.emit('socket_error');
self._remote._trace('server: onerror:', self._opts.url, e.data || e);
self._remote.trace && log.info('onerror:', self._opts.url, e.data || e);
// Most connection errors for WebSockets are conveyed as 'close' events with
// code 1006. This is done for security purposes and therefore unlikely to
@@ -247,7 +248,7 @@ Server.prototype.connect = function() {
ws.onclose = function onClose() {
// If we are no longer the active socket, simply ignore any event
if (ws === self._ws) {
self._remote._trace('server: onclose:', self._opts.url, ws.readyState);
self._remote.trace && log.info('onclose:', self._opts.url, ws.readyState);
self._handleClose();
}
};
@@ -274,7 +275,7 @@ Server.prototype._retryConnect = function() {
function connectionRetry() {
if (self._shouldConnect) {
self._remote._trace('server: retry', self._opts.url);
self._remote.trace && log.info('retry', self._opts.url);
self.connect();
}
};
@@ -351,9 +352,9 @@ Server.prototype._handleMessage = function(message) {
delete self._requests[message.id];
if (!request) {
this._remote._trace('server: UNEXPECTED:', self._opts.url, message);
this._remote.trace && log.info('UNEXPECTED:', self._opts.url, message);
} else if (message.status === 'success') {
this._remote._trace('server: response:', self._opts.url, message);
this._remote.trace && log.info('response:', self._opts.url, message);
request.emit('success', message.result);
@@ -361,7 +362,7 @@ Server.prototype._handleMessage = function(message) {
emitter.emit('response_' + request.message.command, message.result, request, message);
});
} else if (message.error) {
this._remote._trace('server: error:', self._opts.url, message);
this._remote.trace && log.info('error:', self._opts.url, message);
request.emit('error', {
error : 'remoteError',
@@ -372,7 +373,7 @@ Server.prototype._handleMessage = function(message) {
break;
case 'path_find':
this._remote._trace('server: path_find:', self._opts.url, message);
this._remote.trace && log.info('path_find:', self._opts.url, message);
break;
}
@@ -431,7 +432,7 @@ Server.prototype._handleResponseSubscribe = function(message) {
Server.prototype.sendMessage = function(message) {
if (this._ws) {
this._remote._trace('server: request:', this._opts.url, message);
this._remote.trace && log.info('request:', this._opts.url, message);
this._ws.send(JSON.stringify(message));
}
};
@@ -451,7 +452,7 @@ Server.prototype.request = function(request) {
// Only bother if we are still connected.
if (!this._ws) {
this._remote._trace('server: request: DROPPING:', self._opts.url, request.message);
this._remote.trace && log.info('request: DROPPING:', self._opts.url, request.message);
return;
}

View File

@@ -92,18 +92,6 @@ function chunkString(str, n, leftAlign) {
return ret;
};
function logObject(msg) {
var args = Array.prototype.slice.call(arguments, 1);
args = args.map(function(arg) {
return JSON.stringify(arg, null, 2);
});
args.unshift(msg);
console.log.apply(console, args);
};
function assert(assertion, msg) {
if (!assertion) {
throw new Error("Assertion failed" + (msg ? ": "+msg : "."));
@@ -157,7 +145,6 @@ exports.hexToArray = hexToArray;
exports.stringToArray = stringToArray;
exports.stringToHex = stringToHex;
exports.chunkString = chunkString;
exports.logObject = logObject;
exports.assert = assert;
exports.arrayUnique = arrayUnique;
exports.toTimestamp = toTimestamp;

View File

@@ -1,19 +0,0 @@
var exports = module.exports = require('./utils.js');
// We override this function for browsers, because they print objects nicer
// natively than JSON.stringify can.
exports.logObject = function (msg, obj) {
var args = Array.prototype.slice.call(arguments, 1);
args = args.map(function(arg) {
if (/MSIE/.test(navigator.userAgent)) {
return JSON.stringify(arg, null, 2);
} else {
return arg;
}
});
args.unshift(msg);
console.log.apply(console, args);
};