enhance response errors with request/response metadata

This commit is contained in:
spalger
2015-08-04 05:01:18 -07:00
parent a460ef8146
commit de3c00b0dc
3 changed files with 61 additions and 19 deletions

View File

@ -4,7 +4,7 @@ var errors = module.exports;
var canCapture = (typeof Error.captureStackTrace === 'function');
var canStack = !!(new Error()).stack;
function ErrorAbstract(msg, constructor) {
function ErrorAbstract(msg, constructor, metadata) {
this.message = msg;
Error.call(this, this.message);
@ -18,6 +18,20 @@ function ErrorAbstract(msg, constructor) {
else {
this.stack = '';
}
if (metadata) {
_.assign(this, metadata);
this.toString = function () {
return msg + ' :: ' + JSON.stringify(metadata);
};
this.toJSON = function () {
return _.assign({
msg: msg
}, metadata);
};
}
}
errors._Abstract = ErrorAbstract;
_.inherits(ErrorAbstract, Error);
@ -44,8 +58,8 @@ _.inherits(errors.NoConnections, ErrorAbstract);
* Generic Error
* @param {String} [msg] - An error message that will probably end up in a log.
*/
errors.Generic = function Generic(msg) {
ErrorAbstract.call(this, msg || 'Generic Error', errors.Generic);
errors.Generic = function Generic(msg, metadata) {
ErrorAbstract.call(this, msg || 'Generic Error', errors.Generic, metadata);
};
_.inherits(errors.Generic, ErrorAbstract);
@ -149,20 +163,43 @@ var statusCodes = {
_.each(statusCodes, function (name, status) {
var className = _.studlyCase(name);
function StatusCodeError(msg) {
// errors from es now come in two forms, an error string < 2.0 and
// an object >= 2.0
// TODO: remove after dropping support for < 2.0
if (typeof msg === 'object') {
msg = _.reduce(msg.root_cause, function (msg, cause) {
if (msg) msg += ' (and) ';
msg += '[' + cause.type + '] ' + cause.reason;
return msg;
}, '') || msg.reason;
function StatusCodeError(msg, metadata) {
this.status = status;
var esErrObject = null;
if (_.isPlainObject(msg)) {
esErrObject = msg;
msg = null;
}
this.status = status;
ErrorAbstract.call(this, msg || name, StatusCodeError);
if (!esErrObject) {
// errors from es now come in two forms, an error string < 2.0 and
// an object >= 2.0
// TODO: remove after dropping support for < 2.0
ErrorAbstract.call(this, msg || name, StatusCodeError);
return this;
}
msg = [].concat(esErrObject.root_cause || []).reduce(function (memo, cause) {
if (memo) memo += ' (and) ';
memo += '[' + cause.type + '] ' + cause.reason;
var extraData = _.omit(cause, ['type', 'reason']);
if (_.size(extraData)) {
memo += ', with: ' + JSON.stringify(extraData);
}
return memo;
}, '');
if (!msg) {
if (esErrObject.type) msg += '[' + esErrObject.type + '] ';
if (esErrObject.reason) msg += esErrObject.reason;
}
ErrorAbstract.call(this, msg || name, StatusCodeError, metadata);
return this;
}
_.inherits(StatusCodeError, ErrorAbstract);

View File

@ -229,10 +229,15 @@ Transport.prototype.request = function (params, cb) {
&& (status < 200 || status >= 300)
&& (!params.ignore || !_.contains(params.ignore, status))
) {
var errorMetadata = _.pick(params.req, ['path', 'query', 'body']);
errorMetadata.statusCode = status;
errorMetadata.response = body;
if (errors[status]) {
err = new errors[status](parsedBody && parsedBody.error);
err = new errors[status](parsedBody && parsedBody.error, errorMetadata);
} else {
err = new errors.Generic('unknown error');
err = new errors.Generic('unknown error', errorMetadata);
}
}

View File

@ -21,7 +21,7 @@ var implementedFeatures = ['gtelte', 'regex', 'benchmark', 'stash_in_path', 'gro
var ES_VERSION = null;
// core expression for finding a version
var versionExp = '((?:\\d+\\.){0,2}\\d+)(?:\\.\\w+)?|';
var versionExp = '((?:\\d+\\.){0,2}\\d+)(?:[\\.\\-]\\w+)?|';
// match all whitespace within a "regexp" match arg
var reWhitespace_RE = /\s+/g;
@ -432,7 +432,7 @@ YamlDoc.prototype = {
if (catcher) {
if (catcher instanceof RegExp) {
// error message should match the regexp
expect(error.message).to.match(catcher);
expect('' + error).to.match(catcher);
error = null;
} else if (typeof catcher === 'function') {
// error should be an instance of