Moved the curl formatting into the log and changed the arguments for the log event listeneres to

receive both the "message" and the "curlCommand".

Added a "tracer" logger which allows you to create log files that a executable scripts. Those scripts
will write all of the log messages as script comments, and not comment out the curlCommands, so that they
can trace their application and use the generated script to recreate the issue.

Most changes are simply cased by adding the "unused" rule to jshint.
This commit is contained in:
Spencer Alger
2013-11-15 19:10:45 -07:00
parent 20804bb5ab
commit 5bb70fbe58
32 changed files with 185 additions and 229 deletions

View File

@ -1,4 +1,5 @@
{ {
"unused": true,
"node": true, "node": true,
"white": true, "white": true,
"bitwise": false, "bitwise": false,

View File

@ -4,7 +4,6 @@
module.exports = function (grunt) { module.exports = function (grunt) {
var _ = require('lodash'); var _ = require('lodash');
var child_process = require('child_process');
var sharedBrowserfyExclusions = [ var sharedBrowserfyExclusions = [
'when', 'when',
@ -43,7 +42,6 @@ module.exports = function (grunt) {
options: { options: {
require: 'should', require: 'should',
reporter: 'dot', reporter: 'dot',
bail: true,
timeout: 11e3 timeout: 11e3
} }
}, },

View File

@ -23,7 +23,7 @@ module.exports = function (path) {
function rmDirRecursive(path) { function rmDirRecursive(path) {
fs.readdirSync(path).forEach(function (file, index) { fs.readdirSync(path).forEach(function (file) {
var curPath = path + '/' + file; var curPath = path + '/' + file;
if (fs.statSync(curPath).isDirectory()) { // recurse if (fs.statSync(curPath).isDirectory()) { // recurse
rmDirRecursive(curPath); rmDirRecursive(curPath);

View File

@ -64,7 +64,7 @@ function transformFile(entry) {
} }
var urls = _.difference(def.url.paths, aliases[name]); var urls = _.difference(def.url.paths, aliases[name]);
urls = _.map(urls, function (url, i) { urls = _.map(urls, function (url) {
var optionalVars = {}; var optionalVars = {};
var requiredVars = {}; var requiredVars = {};
var param; var param;

View File

@ -1,21 +1,14 @@
var _ = require('../../../src/lib/utils'); var _ = require('../../../src/lib/utils');
var asset = require('assert');
var path = require('path');
var fs = require('fs'); var fs = require('fs');
var mkdirp = require('mkdirp');
var templates = require('./templates'); var templates = require('./templates');
var clean = require('../../clean'); var clean = require('../../clean');
var restSpecUpdated = require('../../rest_spec_updated'); var restSpecUpdated = require('../../rest_spec_updated');
var urlParamRE = /\{(\w+)\}/g;
var outputPath = _.joinPath(__dirname, '../../../src/lib/api.js'); var outputPath = _.joinPath(__dirname, '../../../src/lib/api.js');
var docOutputPath = _.joinPath(__dirname, '../../../docs/api.md'); var docOutputPath = _.joinPath(__dirname, '../../../docs/api.md');
var lastFetchTmp = path.join(__dirname, './last_fetch.tmp');
function download() { function download() {
require('./actions').on('ready', function (actions) { require('./actions').on('ready', function (actions) {
var defs = [];
var namespaces = _.filter(_.map(actions, function (action) { var namespaces = _.filter(_.map(actions, function (action) {
if (~action.location.indexOf('.')) { if (~action.location.indexOf('.')) {
var path = action.location.split('.').slice(0, -1); var path = action.location.split('.').slice(0, -1);

View File

@ -1,8 +1,6 @@
/* jshint maxlen: false */ /* jshint maxlen: false */
var ca = require('./client_action'); var ca = require('./client_action');
var errors = require('./errors');
var api = module.exports = {}; var api = module.exports = {};
api._namespaces = <%= stringify(namespaces) %>;<% api._namespaces = <%= stringify(namespaces) %>;<%

View File

@ -4,48 +4,6 @@ var fs = require('fs');
var path = require('path'); var path = require('path');
/**
* Simple manager to take care of indentation
* @param {number} i - Width of the indentation
* @return {function} - Call this to add a new line to the output
*/
function lines(i) {
function l(line) {
if (line === '') {
// no indent on empty lines
l.lines.push('');
} else if (line === void 0) {
l.lines.push(_.repeat(' ', l.indent) + line);
}
return l;
}
l.lines = [];
l.indent = i || 0;
l.split = function (toSplit) {
_.each(toSplit.split(/\r?\n/), l);
return l;
};
l.in = function (line) {
l.indent += 2;
return l(line);
};
l.out = function (line) {
l.indent -= 2;
return l(line);
};
l.toString = function () {
return l.lines.join('\n');
};
return l;
}
/** /**
* we want strings in code to use single-quotes, so this will JSON encode vars, but then * we want strings in code to use single-quotes, so this will JSON encode vars, but then
* modify them to follow our code standards. * modify them to follow our code standards.

View File

@ -45,7 +45,6 @@ if (argv.host) {
} }
var client = new es.Client(clientConfig); var client = new es.Client(clientConfig);
var log = client.config.log;
console.log('Generating', count, 'events across ±', days, 'days'); console.log('Generating', count, 'events across ±', days, 'days');

View File

@ -1,10 +1,9 @@
var _ = require('../../../../src/lib/utils'), var _ = require('../../../../src/lib/utils');
WeightedList = require('./weighted_list'), var WeightedList = require('./weighted_list');
RandomList = require('./random_list'), var RandomList = require('./random_list');
IpGenerator = require('./ip_generator'), var IpGenerator = require('./ip_generator');
Stochator = require('./stochator'), var Stochator = require('./stochator');
moment = require('moment'), var dayMs = 86400000;
dayMs = 86400000;
exports.make = function (startingMoment, endingMoment) { exports.make = function (startingMoment, endingMoment) {

View File

@ -4,8 +4,6 @@
module.exports = RandomList; module.exports = RandomList;
var _ = require('../../../../src/lib/utils');
function RandomList(list) { function RandomList(list) {
this.get = function () { this.get = function () {
return list[Math.round(Math.random() * list.length)]; return list[Math.round(Math.random() * list.length)];

View File

@ -7,7 +7,6 @@ var path = require('path');
var jsYaml = require('js-yaml'); var jsYaml = require('js-yaml');
var spec = require('../../get_spec'); var spec = require('../../get_spec');
var clean = require('../../clean'); var clean = require('../../clean');
var _ = require('../../../src/lib/utils');
var restSpecUpdated = require('../../rest_spec_updated'); var restSpecUpdated = require('../../rest_spec_updated');
var testFile = path.resolve(__dirname, '../../../test/integration/yaml_suite/yaml_tests.json'); var testFile = path.resolve(__dirname, '../../../test/integration/yaml_suite/yaml_tests.json');

View File

@ -1,5 +1,4 @@
var http = require('http'), var http = require('http');
async = require('async');
var server = http.createServer(function (req, resp) { var server = http.createServer(function (req, resp) {
var closed, count = 0; var closed, count = 0;

View File

@ -1,46 +1,70 @@
var es = require('../src/elasticsearch'); var es = require('../src/elasticsearch');
var async = require('async'); var async = require('async');
var argv = require('optimist').default({
indx: 'test-docs',
type: 'test-doc',
warm: 10000,
docs: 100000,
sync: false,
sock: 100
})
.boolean('sync')
.argv;
function getMs() { function hrtime(start) {
var hr = process.hrtime(); var hr = start ? process.hrtime(start) : process.hrtime();
return (hr[0] * 1e9 + hr[1]) / 1e6; return start ? Math.round(((hr[0] * 1e9 + hr[1]) / 1e6) * 100) / 100 : hr;
} }
var client = new es.Client({ var client = new es.Client({
hosts: 'localhost:9200', hosts: 'localhost:9200',
log: null, log: null,
maxSockets: 100 maxSockets: argv.sock
}); });
async.series([ async.series([
function (done) { function (done) {
console.log('clearing existing "test-docs" indices'); console.log('removing existing "%s" index', argv.indx);
client.indices.delete({ client.indices.delete({
index: 'test-docs', index: argv.indx,
ignore: 404 ignore: 404
}, done); }, done);
}, },
function (done) { function (done) {
console.log('waiting for cluster'); console.log('creating new "%s" index', argv.indx);
client.cluster.health({ client.indices.create({
wait_for_status: 'yellow' index: argv.indx,
body: {}
}, done); }, done);
}, },
function (done) { function (done) {
var times = 1e4; console.log('warnming up index with %d docs', argv.warm);
console.log('creating %d docs', times); async.times(argv.warm, function (i, done) {
var start = getMs();
async.times(times, function (i, done) {
client.index({ client.index({
index: 'test-docs', index: argv.indx,
type: 'test-doc', type: argv.type,
body: {}
}, done);
}, done);
},
function (done) {
console.log('waiting for cluster to go yellow');
client.cluster.health({
waitForStatus: 'yellow'
}, done);
},
function (done) {
console.log('creating %d docs ' + (async.sync ? 'in series' : argv.sock + ' requests at a time'), argv.docs);
var start = hrtime();
async[argv.sync ? 'timesSeries' : 'times'](argv.docs, function (i, done) {
client.index({
index: argv.indx,
type: argv.type,
body: {} body: {}
}, done); }, done);
}, function (err) { }, function (err) {
console.log('complete in', Math.round((getMs() - start) * 100) / 100, 'ms'); console.log('complete in', hrtime(start), 'ms');
if (err) { done(err);
client.config.log.error(err);
}
}); });
} }
], function (err) { ], function (err) {

View File

@ -1,8 +1,6 @@
/* jshint maxlen: false */ /* jshint maxlen: false */
var ca = require('./client_action'); var ca = require('./client_action');
var errors = require('./errors');
var api = module.exports = {}; var api = module.exports = {};
api._namespaces = ['cluster', 'indices']; api._namespaces = ['cluster', 'indices'];

View File

@ -52,7 +52,7 @@ function Client(config) {
} }
} }
Client.prototype = _.clone(api); Client.prototype = api;
/** /**
* Ping some node to ensure that the cluster is available in some respect * Ping some node to ensure that the cluster is available in some respect

View File

@ -8,9 +8,7 @@ module.exports = function ClientAction(spec, client) {
}; };
}; };
var errors = require('./errors');
var _ = require('./utils'); var _ = require('./utils');
var urlParamRE = /\{(\w+)\}/g;
var castType = { var castType = {
enum: function (param, val, name) { enum: function (param, val, name) {
@ -45,7 +43,7 @@ var castType = {
return !!val; return !!val;
} }
}, },
boolean: function (param, val, name) { boolean: function (param, val) {
val = _.isString(val) ? val.toLowerCase() : val; val = _.isString(val) ? val.toLowerCase() : val;
return (val === 'no' || val === 'off') ? false : !!val; return (val === 'no' || val === 'off') ? false : !!val;
}, },
@ -139,7 +137,6 @@ function exec(transport, spec, params, cb) {
} }
var request = {}; var request = {};
var parts = {};
var query = {}; var query = {};
var i; var i;
@ -147,8 +144,6 @@ function exec(transport, spec, params, cb) {
return _.nextTick(cb, new TypeError('A request body is required.')); return _.nextTick(cb, new TypeError('A request body is required.'));
} }
params.body && (request.body = params.body);
params.ignore && (request.ignore = _.isArray(params.ignore) ? params.ignore : [params.ignore]);
if (params.timeout === void 0) { if (params.timeout === void 0) {
request.timeout = 10000; request.timeout = 10000;
} else { } else {
@ -156,6 +151,8 @@ function exec(transport, spec, params, cb) {
} }
// copy over some properties from the spec // copy over some properties from the spec
params.body && (request.body = params.body);
params.ignore && (request.ignore = _.isArray(params.ignore) ? params.ignore : [params.ignore]);
spec.bulkBody && (request.bulkBody = true); spec.bulkBody && (request.bulkBody = true);
spec.castExists && (request.castExists = true); spec.castExists && (request.castExists = true);

View File

@ -6,7 +6,6 @@
*/ */
module.exports = ClientConfig; module.exports = ClientConfig;
var url = require('url');
var _ = require('./utils'); var _ = require('./utils');
var Host = require('./host'); var Host = require('./host');
var selectors = require('./selectors'); var selectors = require('./selectors');
@ -20,6 +19,7 @@ if (process.browser) {
connectors.Http = require('./connectors/http'); connectors.Http = require('./connectors/http');
} }
// remove connectors that have been excluded in the build
_.each(connectors, function (conn, name) { _.each(connectors, function (conn, name) {
if (typeof conn !== 'function') { if (typeof conn !== 'function') {
delete connectors[name]; delete connectors[name];
@ -30,8 +30,7 @@ var serializers = {
Json: require('./serializers/json') Json: require('./serializers/json')
}; };
var extractHostPartsRE = /\[([^:]+):(\d+)]/; var extractHostPartsRE = /\[([^:]+):(\d+)\]/;
var hostProtocolRE = /^([a-z]+:)?\/\//;
var defaultClasses = { var defaultClasses = {
log: require('./log'), log: require('./log'),
@ -62,17 +61,18 @@ var defaultConfig = {
timeout: 10000, timeout: 10000,
deadTimeout: 60000, deadTimeout: 60000,
maxSockets: 10, maxSockets: 10,
// transforms the response from /_cluster/nodes
nodesToHostCallback: function (nodes) { nodesToHostCallback: function (nodes) {
var hosts = []; var hosts = [];
_.each(nodes, function (node, id) { _.each(nodes, function (node, id) {
var hostnameMatches = extractHostPartsRE.exec(node.host); var hostnameMatches = extractHostPartsRE.exec(node.http_address);
hosts.push({ hosts.push({
host: hostnameMatches[1], host: hostnameMatches[1],
port: hostnameMatches[2], port: hostnameMatches[2],
_meta: { _meta: {
id: id, id: id,
name: node.name, name: node.name,
servername: node.host, hostname: node.hostname,
version: node.version version: node.version
} }
}); });
@ -128,9 +128,6 @@ function ClientConfig(config) {
} }
ClientConfig.prototype.prepareHosts = function (hosts) { ClientConfig.prototype.prepareHosts = function (hosts) {
var host;
var i;
if (!_.isArray(hosts)) { if (!_.isArray(hosts)) {
hosts = [hosts]; hosts = [hosts];
} }

View File

@ -9,9 +9,6 @@
module.exports = ConnectionPool; module.exports = ConnectionPool;
var _ = require('./utils'); var _ = require('./utils');
var selectors = require('./selectors');
var EventEmitter = require('events').EventEmitter;
var errors = require('./errors');
var Host = require('./host'); var Host = require('./host');
function ConnectionPool(config) { function ConnectionPool(config) {
@ -37,7 +34,7 @@ ConnectionPool.prototype.select = function (cb) {
} }
} }
} else { } else {
cb(); _.nextTick(cb, null, this.connections.dead[0]);
} }
}; };
@ -45,9 +42,14 @@ ConnectionPool.prototype.onStatusChanged = _.handler(function (status, oldStatus
var from, to, index; var from, to, index;
if (oldStatus === status) { if (oldStatus === status) {
return true; if (status === 'dead') {
// we want to remove the connection from it's current possition and move it to the end
status = 'redead';
} else { } else {
this.config.log.info('connection id:', connection.__id, 'is', status); return true;
}
} else {
this.config.log.info('connection id:', connection.id, 'is', status);
} }
switch (status) { switch (status) {
@ -59,6 +61,10 @@ ConnectionPool.prototype.onStatusChanged = _.handler(function (status, oldStatus
from = this.connections.alive; from = this.connections.alive;
to = this.connections.dead; to = this.connections.dead;
break; break;
case 'redead':
from = this.connections.dead;
to = this.connections.dead;
break;
case 'closed': case 'closed':
from = this.connections[oldStatus]; from = this.connections[oldStatus];
break; break;
@ -79,17 +85,17 @@ ConnectionPool.prototype.onStatusChanged = _.handler(function (status, oldStatus
} }
}); });
ConnectionPool.prototype._add = function (connection) { ConnectionPool.prototype.addConnection = function (connection) {
if (!this.index[connection.__id]) { if (!this.index[connection.id]) {
this.index[connection.__id] = connection; this.index[connection.id] = connection;
connection.on('status changed', this.bound.onStatusChanged); connection.on('status changed', this.bound.onStatusChanged);
connection.setStatus('alive'); connection.setStatus('alive');
} }
}; };
ConnectionPool.prototype._remove = function (connection) { ConnectionPool.prototype.removeConnection = function (connection) {
if (this.index[connection.__id]) { if (this.index[connection.id]) {
delete this.index[connection.__id]; delete this.index[connection.id];
connection.setStatus('closed'); connection.setStatus('closed');
connection.removeListener('status changed', this.bound.onStatusChanged); connection.removeListener('status changed', this.bound.onStatusChanged);
} }
@ -110,13 +116,13 @@ ConnectionPool.prototype.setNodes = function (nodeConfigs) {
delete toRemove[id]; delete toRemove[id];
} else { } else {
connection = new this.config.connectionClass(node, this.config); connection = new this.config.connectionClass(node, this.config);
connection.__id = id; connection.id = id;
this._add(connection); this.addConnection(connection);
} }
} }
} }
_.each(toRemove, this._remove, this); _.each(toRemove, this.removeConnection, this);
}; };
ConnectionPool.prototype.close = function () { ConnectionPool.prototype.close = function () {

View File

@ -10,16 +10,12 @@ var _ = require('../utils');
var ConnectionAbstract = require('../connection'); var ConnectionAbstract = require('../connection');
var ConnectionFault = require('../errors').ConnectionFault; var ConnectionFault = require('../errors').ConnectionFault;
/* global angular */
function AngularConnector(host, config) { function AngularConnector(host, config) {
ConnectionAbstract.call(this, host, config); ConnectionAbstract.call(this, host, config);
} }
_.inherits(AngularConnector, ConnectionAbstract); _.inherits(AngularConnector, ConnectionAbstract);
AngularConnector.prototype.request = function (params, cb) { AngularConnector.prototype.request = function (params, cb) {
var timeoutId;
this.$http({ this.$http({
method: params.method, method: params.method,
url: this.host.makeUrl(params), url: this.host.makeUrl(params),
@ -31,7 +27,6 @@ AngularConnector.prototype.request = function (params, cb) {
}, function (err) { }, function (err) {
cb(new ConnectionFault(err.message)); cb(new ConnectionFault(err.message));
}); });
}; };
// must be overwritten before this connection can be used // must be overwritten before this connection can be used

View File

@ -8,22 +8,21 @@
*/ */
module.exports = HttpConnector; module.exports = HttpConnector;
var http = require('http'); var handles = {
var https = require('https'); http: require('http'),
https: require('https')
};
var _ = require('../utils'); var _ = require('../utils');
var errors = require('../errors'); var errors = require('../errors');
var qs = require('querystring'); var qs = require('querystring');
var KeepAliveAgent = require('agentkeepalive/lib/agent'); var KeepAliveAgent = require('agentkeepalive/lib/agent');
var ConnectionAbstract = require('../connection'); var ConnectionAbstract = require('../connection');
var defaultHeaders = {
'connection': 'keep-alive'
};
function HttpConnector(host, config) { function HttpConnector(host, config) {
ConnectionAbstract.call(this, host, config); ConnectionAbstract.call(this, host, config);
this.hand = require(this.host.protocol); this.hand = handles[this.host.protocol];
this.agent = new KeepAliveAgent({ this.agent = new KeepAliveAgent({
maxSockets: 1, maxSockets: 1,
maxKeepAliveRequests: 0, // max requests per keepalive socket, default is 0, no limit. maxKeepAliveRequests: 0, // max requests per keepalive socket, default is 0, no limit.
@ -58,7 +57,6 @@ HttpConnector.prototype.makeReqParams = function (params) {
}; };
var query = this.host.query ? this.host.query : null; var query = this.host.query ? this.host.query : null;
var queryStr;
if (typeof query === 'string') { if (typeof query === 'string') {
query = qs.parse(query); query = qs.parse(query);
@ -85,9 +83,7 @@ HttpConnector.prototype.request = function (params, cb) {
var incoming; var incoming;
var timeoutId; var timeoutId;
var request; var request;
var requestId = this.requestCount;
var response; var response;
var responseStarted = false;
var status = 0; var status = 0;
var timeout = params.timeout || this.config.timeout; var timeout = params.timeout || this.config.timeout;
var log = this.config.log; var log = this.config.log;

View File

@ -10,7 +10,7 @@ module.exports = JqueryConnector;
function JqueryConnector() {} function JqueryConnector() {}
JqueryConnector.prototype.request = function (params, cb) { JqueryConnector.prototype.request = function (params, cb) {
var $xhr = jQuery.ajax(params).done(cb); jQuery.ajax(params).done(cb);
}; };

View File

@ -32,6 +32,7 @@ if (typeof XMLHttpRequest !== 'undefined') {
} else { } else {
// find the first MS implementation available // find the first MS implementation available
getXhr = _.first(['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], function (appName) { getXhr = _.first(['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], function (appName) {
/* jshint unused: false */
try { try {
var test = new window.ActiveXObject(appName); var test = new window.ActiveXObject(appName);
return function () { return function () {
@ -61,7 +62,7 @@ XhrConnector.prototype.request = function (params, cb) {
xhr.open(params.method, url, async); xhr.open(params.method, url, async);
} }
xhr.onreadystatechange = function (e) { xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
clearTimeout(timeoutId); clearTimeout(timeoutId);
log.trace(params.method, url, params.body, xhr.responseText, xhr.status); log.trace(params.method, url, params.body, xhr.responseText, xhr.status);

View File

@ -9,7 +9,8 @@ if (process.browser) {
var loggers = { var loggers = {
File: require('./loggers/file'), File: require('./loggers/file'),
Stream: require('./loggers/file'), Stream: require('./loggers/file'),
Stdio: require('./loggers/stdio') Stdio: require('./loggers/stdio'),
Tracer: require('./loggers/tracer')
}; };
} }
@ -290,8 +291,27 @@ Log.prototype.trace = function (method, requestUrl, body, responseBody, response
requestUrl.pathname = requestUrl.path.split('?').shift(); requestUrl.pathname = requestUrl.path.split('?').shift();
} }
return this.emit('trace', method, url.format(requestUrl), body, responseBody, responseStatus); requestUrl = url.format(requestUrl);
var message = '<- ' + responseStatus + '\n' + prettyJSON(responseBody);
/* jshint quotmark: double */
var curlCall = "curl '" + requestUrl.replace(/'/g, "\\'") + "' -X" + method.toUpperCase();
if (body) {
curlCall += " -d '" + prettyJSON(body) + "'";
}
/* jshint quotmark: single */
return this.emit('trace', message, curlCall);
} }
}; };
function prettyJSON(body) {
try {
return JSON.stringify(JSON.parse(body), null, ' ').replace(/'/g, '\\\'');
} catch (e) {
return body || '';
}
}
module.exports = Log; module.exports = Log;

View File

@ -1,5 +1,4 @@
var Log = require('./log'), var _ = require('./utils');
_ = require('./utils');
/** /**
* Abstract class providing common functionality to loggers * Abstract class providing common functionality to loggers
@ -145,12 +144,7 @@ LoggerAbstract.prototype.onDebug = _.handler(function (msg) {
* @param {String} msg - The message to be logged * @param {String} msg - The message to be logged
* @return {undefined} * @return {undefined}
*/ */
LoggerAbstract.prototype.onTrace = _.handler(function (method, url, body, responseBody, responseStatus) { LoggerAbstract.prototype.onTrace = _.handler(function (message) {
var message = 'curl "' + url.replace(/"/g, '\\"') + '" -X' + method.toUpperCase();
if (body) {
message += ' -d "' + body.replace(/"/g, '\\"') + '"';
}
message += '\n<- ' + responseStatus + '\n' + responseBody;
this.write('TRACE', message); this.write('TRACE', message);
}); });

View File

@ -16,6 +16,7 @@ var LoggerAbstract = require('../logger');
var _ = require('../utils'); var _ = require('../utils');
function Console(config, bridge) { function Console(config, bridge) {
// call my super
LoggerAbstract.call(this, config, bridge); LoggerAbstract.call(this, config, bridge);
// config/state // config/state
@ -31,9 +32,11 @@ _.inherits(Console, LoggerAbstract);
Console.prototype.setupListeners = function (levels) { Console.prototype.setupListeners = function (levels) {
// since some of our functions are bound a bit differently (to the console) // since some of our functions are bound a bit differently (to the console)
// create some of the bound properties manually // create some of the bound properties manually
this.bound.onError = this.onError;
this.bound.onWarning = this.onWarning; this.bound.onWarning = this.onWarning;
this.bound.onInfo = this.onInfo; this.bound.onInfo = this.onInfo;
this.bound.onDebug = this.onDebug; this.bound.onDebug = this.onDebug;
this.bound.onTrace = this.onTrace;
// call the super method // call the super method
LoggerAbstract.prototype.setupListeners.call(this, levels); LoggerAbstract.prototype.setupListeners.call(this, levels);
@ -47,13 +50,13 @@ Console.prototype.setupListeners = function (levels) {
* @param {Error} e - The Error object to log * @param {Error} e - The Error object to log
* @return {undefined} * @return {undefined}
*/ */
Console.prototype.onError = _.handler(function (e) { Console.prototype.onError = function (e) {
if (console.error && console.trace) { if (console.error && console.trace) {
console.error(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message); console.error(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message);
} else { } else {
console.log(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message); console.log(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message);
} }
}); };
/** /**
* Handler for the bridges "warning" event * Handler for the bridges "warning" event
@ -97,11 +100,6 @@ Console.prototype.onDebug = function (msg) {
* @private * @private
* @return {undefined} * @return {undefined}
*/ */
Console.prototype.onTrace = _.handler(function (method, url, body, responseBody, responseStatus) { Console.prototype.onTrace = function (message, curlCall) {
var message = 'curl "' + url.replace(/"/g, '\\"') + '" -X' + method.toUpperCase(); console.log('TRACE:\n' + curlCall + '\n' + message);
if (body) { };
message += ' -d "' + body.replace(/"/g, '\\"') + '"';
}
message += '\n<- ' + responseStatus + '\n' + responseBody;
console.log('TRACE:\n' + message + '\n');
});

View File

@ -11,19 +11,20 @@
module.exports = File; module.exports = File;
var StreamLogger = require('./stream'), var StreamLogger = require('./stream');
_ = require('../utils'), var _ = require('../utils');
fs = require('fs'); var fs = require('fs');
function File(config, bridge) { function File(config, bridge) {
this.path = config.path; // setup the stream before calling the super
this.path = config.path || 'elasticsearch.log';
config.stream = fs.createWriteStream(config.path, { config.stream = fs.createWriteStream(this.path, {
flags: 'a', flags: 'a',
encoding: 'utf8' encoding: 'utf8'
}); });
File.callSuper(this, arguments); // call my super
StreamLogger.call(this, config, bridge);
} }
_.inherits(File, StreamLogger); _.inherits(File, StreamLogger);

View File

@ -41,7 +41,8 @@ var defaultColors = {
}; };
function Stdio(config, bridge) { function Stdio(config, bridge) {
Stdio.callSuper(this, arguments); // call my super
LoggerAbstract.call(this, config, bridge);
// config/state // config/state
this.color = Boolean(_.has(config, 'color') ? config.color : chalk.supportsColor); this.color = Boolean(_.has(config, 'color') ? config.color : chalk.supportsColor);
@ -124,18 +125,6 @@ Stdio.prototype.onDebug = _.handler(function (msg) {
* @private * @private
* @return {undefined} * @return {undefined}
*/ */
Stdio.prototype.onTrace = _.handler(function (method, url, body, resp, status) { Stdio.prototype.onTrace = _.handler(function (message, curlCall) {
var message = 'curl "' + url.replace(/"/g, '\\"') + '" -X' + method.toUpperCase(); this.write(process.stdout, 'TRACE', this.colors.trace, curlCall + '\n' + message);
if (body) {
message += ' -d "' + body.replace(/"/g, '\\"') + '"';
}
message += '\n<- ';
if (this.color) {
message += this.colors.traceStatus(status);
} else {
message += status;
}
message += '\n' + resp;
this.write(process.stdout, 'TRACE', this.colors.trace, message);
}); });

View File

@ -12,14 +12,12 @@
module.exports = Stream; module.exports = Stream;
var LoggerAbstract = require('../logger'), var LoggerAbstract = require('../logger');
nodeStreams = require('stream'), var _ = require('../utils');
_ = require('../utils'),
fs = require('fs');
function Stream(config, bridge) { function Stream(config, bridge) {
Stream.callSuper(this, arguments); // call my super
_.makeBoundMethods(this); LoggerAbstract.call(this, config, bridge);
if (config.stream.write && config.stream.end) { if (config.stream.write && config.stream.end) {
this.stream = config.stream; this.stream = config.stream;

40
src/lib/loggers/tracer.js Executable file
View File

@ -0,0 +1,40 @@
/**
* Logger that writes to a file, but the file can be executed as a shell script,
* meaning everything but the curl commands are commented out
*
* @class Loggers.Tracer
* @extends StreamLogger
* @constructor
* @param {Object} config - The configuration for the Logger (See LoggerAbstract for generic options)
* @param {String} config.path - The location to write
* @param {Log} bridge - The object that triggers logging events, which we will record
*/
module.exports = Tracer;
var FileLogger = require('./file');
var _ = require('../utils');
function Tracer(config, bridge) {
// call my super
FileLogger.call(this, config, bridge);
}
_.inherits(Tracer, FileLogger);
Tracer.prototype.onTrace = _.handler(function (message, curlCall) {
this.write('TRACE', message, curlCall);
});
function comment(str) {
return _.map(str.split(/\r?\n/g), function (line) {
return '# ' + line;
}).join('\n');
}
Tracer.prototype.write = function (label, message, curlCall) {
this.stream.write(
comment(label + ': ' + this.timestamp()) + '\n' + (curlCall ? curlCall + '\n' : '') +
comment(message) + '\n\n',
'utf8'
);
};

View File

@ -140,8 +140,9 @@ Transport.prototype.request = function (params, cb) {
abort: abortRequest abort: abortRequest
}; };
} else { } else {
request = when.defer(); var defer = when.defer();
request.abort = abortRequest; defer.promise.abort = abortRequest;
request = defer.promise;
} }
return request; return request;

View File

@ -1,6 +1,6 @@
var path = require('path'), var path = require('path');
_ = require('lodash'), var _ = require('lodash');
nodeUtils = require('util'); var nodeUtils = require('util');
/** /**
* Custom utils library, basically a modified version of [lodash](http://lodash.com/docs) + * Custom utils library, basically a modified version of [lodash](http://lodash.com/docs) +
@ -120,7 +120,6 @@ utils.ucfirst = function (word) {
*/ */
function adjustWordCase(firstWordCap, otherWordsCap, sep) { function adjustWordCase(firstWordCap, otherWordsCap, sep) {
return function (string) { return function (string) {
var inWord = false;
var i = 0; var i = 0;
var words = []; var words = [];
var word = ''; var word = '';

View File

@ -1,40 +0,0 @@
/* JSON Serializer tests */
var JsonSerializer = require('../../src/lib/serializers/Json');
describe('json serializer', function () {
var json;
beforeEach(function () {
json = new JsonSerializer();
});
it('creates simple json strings', function () {
json.serialize({foo: true}).should.eql('{"foo":true}');
});
it('creates pretty json strings', function () {
json.serialize({foo: true, bake: 'cake', 'with': ['bacon']}, null, ' ')
.should.eql(['{',
' "foo": true,',
' "bake": "cake",',
' "with": [',
' "bacon"',
' ]',
'}'].join('\n'));
});
it('reads simple json strings', function () {
json.unserialize('{"foo":true}').should.eql({ foo: true });
});
it('does not create date objects', function () {
json
.unserialize('{"date":"2012-04-23T18:25:43.511Z"}')
.should.eql({
date: '2012-04-23T18:25:43.511Z'
});
});
});