Skip to content

Commit

Permalink
feat: send error context as custom data (#870)
Browse files Browse the repository at this point in the history
  • Loading branch information
waltjones authored Jul 7, 2020
1 parent d50272d commit aaf6770
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 1 deletion.
18 changes: 18 additions & 0 deletions src/browser/transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ function handleItemWithError(item, options, callback) {
if (item.err) {
try {
item.stackInfo = item.err._savedStackTrace || errorParser.parse(item.err, item.skipFrames);

if (options.addErrorContext) {
addErrorContext(item);
}
} catch (e) {
logger.error('Error while parsing the error object.', e);
try {
Expand All @@ -32,6 +36,20 @@ function handleItemWithError(item, options, callback) {
callback(null, item);
}

function addErrorContext(item) {
var chain = [];
var err = item.err;

chain.push(err);

while (err.nested) {
err = err.nested;
chain.push(err);
}

_.addErrorContext(item, chain);
}

function ensureItemHasSomethingToSay(item, options, callback) {
if (!item.message && !item.stackInfo && !item.custom) {
callback(new Error('No message, stack info, or custom data'), null);
Expand Down
4 changes: 4 additions & 0 deletions src/react-native/transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ function handleItemWithError(item, options, callback) {
return callback(null, item);
}

if (options.addErrorContext) {
_.addErrorContext(item, [item.err]);
}

var err = item.err;
var parsedError = errorParser.parse(err);
var guess = errorParser.guessErrorClass(parsedError.message);
Expand Down
4 changes: 4 additions & 0 deletions src/server/transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ function handleItemWithError(item, options, callback) {
} while (err !== undefined);
item.stackInfo = chain;

if (options.addErrorContext) {
_.addErrorContext(item, errors);
}

var cb = function(e) {
if (e) {
item.message = item.err.message || item.err.description || item.message || String(item.err);
Expand Down
22 changes: 22 additions & 0 deletions src/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,27 @@ function setCustomItemKeys(item, custom) {
}
}

function addErrorContext(item, errors) {
var custom = item.data.custom || {};
var contextAdded = false;

try {
for (var i = 0; i < errors.length; ++i) {
if (errors[i].hasOwnProperty('rollbarContext')) {
custom = merge(custom, errors[i].rollbarContext);
contextAdded = true;
}
}

// Avoid adding an empty object to the data.
if (contextAdded) {
item.data.custom = custom;
}
} catch (e) {
item.diagnostic.error_context = 'Failed: ' + e.message;
}
}

var TELEMETRY_TYPES = ['log', 'network', 'dom', 'navigation', 'error', 'manual'];
var TELEMETRY_LEVELS = ['critical', 'error', 'warning', 'info', 'debug'];

Expand Down Expand Up @@ -776,6 +797,7 @@ function handleOptions(current, input, payload) {
module.exports = {
addParamsAndAccessTokenToPath: addParamsAndAccessTokenToPath,
createItem: createItem,
addErrorContext: addErrorContext,
createTelemetryEvent: createTelemetryEvent,
filterIp: filterIp,
formatArgsAsString: formatArgsAsString,
Expand Down
27 changes: 27 additions & 0 deletions test/browser.rollbar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,33 @@ describe('log', function() {
done();
})

it('should add custom data when called with error context', function(done) {
var server = window.server;
stubResponse(server);
server.requests.length = 0;

var options = {
accessToken: 'POST_CLIENT_ITEM_TOKEN',
addErrorContext: true
};
var rollbar = window.rollbar = new Rollbar(options);

var err = new Error('test error');
err.rollbarContext = { err: 'test' };

rollbar.error(err, { 'foo': 'bar' });

server.respond();

var body = JSON.parse(server.requests[0].requestBody);

expect(body.data.body.trace.exception.message).to.eql('test error');
expect(body.data.custom.foo).to.eql('bar');
expect(body.data.custom.err).to.eql('test');

done();
})

it('should send message when called with only null arguments', function(done) {
var server = window.server;
stubResponse(server);
Expand Down
20 changes: 19 additions & 1 deletion test/browser.transforms.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,13 +426,31 @@ describe('addBody', function() {
expect(i.stackInfo).to.be.ok();
});
t.addBody(item, options, function(e, i) {
console.log('body:', i.data.body)
expect(i.data.body.trace_chain.length).to.eql(2);
expect(i.data.body.trace_chain[0].exception.message).to.eql('test error');
expect(i.data.body.trace_chain[1].exception.message).to.eql('nested error');
done(e);
});
});
it('should create add error context as custom data', function(done) {
var nestedErr = new Error('nested error');
nestedErr.rollbarContext = { err1: 'nested context' };
var err = new Error('test error');
err.rollbarContext = { err2: 'error context' };
err.nested = nestedErr;
var args = ['a message', err];
var item = itemFromArgs(args);
var options = { addErrorContext: true };
t.handleItemWithError(item, options, function(e, i) {
expect(i.stackInfo).to.be.ok();
});
t.addBody(item, options, function(e, i) {
expect(i.data.body.trace_chain.length).to.eql(2);
expect(i.data.custom.err1).to.eql('nested context');
expect(i.data.custom.err2).to.eql('error context');
done(e);
});
});
});
});

Expand Down
30 changes: 30 additions & 0 deletions test/server.transforms.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,36 @@ vows.describe('transforms')
assert.equal(trace_chain[0].exception.message, 'nested-message');
assert.equal(trace_chain[1].exception.class, 'ReferenceError');
}
},
'with error context': {
topic: function (options) {
var test = function() {
var x = thisVariableIsNotDefined;
};
var err;
try {
test();
} catch (e) {
err = new CustomError('nested-message', e);
e.rollbarContext = { err1: 'nested context' };
err.rollbarContext = { err2: 'error context' };
}
var item = {
data: {body: {}},
err: err
};
options.addErrorContext = true;
t.handleItemWithError(item, options, this.callback);
},
'should not error': function(err, item) {
assert.ifError(err);
},
'should add the error context': function(err, item) {
var trace_chain = item.stackInfo;
assert.lengthOf(trace_chain, 2);
assert.equal(item.data.custom.err1, 'nested context');
assert.equal(item.data.custom.err2, 'error context');
}
}
}
}
Expand Down

0 comments on commit aaf6770

Please sign in to comment.