Skip to content

Commit

Permalink
captureMessage can attach stack trace via stacktrace: true option (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
benvinegar authored Aug 26, 2016
1 parent 4a06c04 commit e8040b1
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ module.exports = function(grunt) {
dest: 'build/raven.test.js',
options: {
browserifyOptions: {
debug: true // source maps
debug: false// source maps
},
ignore: ['react-native'],
plugin: [proxyquire.plugin]
Expand Down
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<button onclick="divide(1, 0)">Sourcemap breakage</button>
<button onclick="derp()">window.onerror</button>
<button onclick="testOptions()">test options</button>
<button onclick="testSynthetic()">test synthetic</button>
<button onclick="throwString()">throw string</button>
<button onclick="showDialog()">show dialog</button>
<button onclick="blobExample()">blob example</button>
Expand Down
6 changes: 6 additions & 0 deletions example/scratch.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ function showDialog() {
Raven.showReportDialog();
}

function testSynthetic() {
Raven.captureMessage('synthetic', {
stacktrace: true
});
}

function blobExample() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'stack.js');
Expand Down
86 changes: 67 additions & 19 deletions src/raven.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,12 @@ Raven.prototype = {
*/
captureException: function(ex, options) {
// If not an Error is passed through, recall as a message instead
if (!isError(ex)) return this.captureMessage(ex, options);
if (!isError(ex)) {
return this.captureMessage(ex, objectMerge({
trimHeadFrames: 1,
stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
}, options));
}

// Store the raw exception object for potential debugging and introspection
this._lastCapturedException = ex;
Expand Down Expand Up @@ -362,12 +367,41 @@ Raven.prototype = {
return;
}

var data = objectMerge({
message: msg + '' // Make sure it's actually a string
}, options);

if (options && options.stacktrace) {
var ex;
// create a stack trace from this point; just trim
// off extra frames so they don't include this function call (or
// earlier Raven.js library fn calls)
try {
throw new Error(msg);
} catch (ex1) {
ex = ex1;
}

// null exception name so `Error` isn't prefixed to msg
ex.name = null;

options = objectMerge({
// fingerprint on msg, not stack trace (legacy behavior, could be
// revisited)
fingerprint: msg,
trimHeadFrames: (options.trimHeadFrames || 0) + 1
}, options);

var stack = TraceKit.computeStackTrace(ex);
var frames = this._prepareFrames(stack, options);
data.stacktrace = {
// Sentry expects frames oldest to newest
frames: frames.reverse()
}
}

// Fire away!
this._send(
objectMerge({
message: msg + '' // Make sure it's actually a string
}, options)
);
this._send(data);

return this;
},
Expand Down Expand Up @@ -1066,17 +1100,7 @@ Raven.prototype = {
},

_handleStackInfo: function(stackInfo, options) {
var self = this;
var frames = [];

if (stackInfo.stack && stackInfo.stack.length) {
each(stackInfo.stack, function(i, stack) {
var frame = self._normalizeFrame(stack);
if (frame) {
frames.push(frame);
}
});
}
var frames = this._prepareFrames(stackInfo, options);

this._triggerEvent('handle', {
stackInfo: stackInfo,
Expand All @@ -1088,11 +1112,36 @@ Raven.prototype = {
stackInfo.message,
stackInfo.url,
stackInfo.lineno,
frames.slice(0, this._globalOptions.stackTraceLimit),
frames,
options
);
},

_prepareFrames: function(stackInfo, options) {
var self = this;
var frames = [];
if (stackInfo.stack && stackInfo.stack.length) {
each(stackInfo.stack, function(i, stack) {
var frame = self._normalizeFrame(stack);
if (frame) {
frames.push(frame);
}
});

// e.g. frames captured via captureMessage throw
if (options && options.trimHeadFrames) {
for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) {
frames[j].in_app = false;
}
// ... delete to prevent from appearing in outbound payload
delete options.trimHeadFrames;
}
}
frames = frames.slice(0, this._globalOptions.stackTraceLimit);
return frames;
},


_normalizeFrame: function(frame) {
if (!frame.url) return;

Expand All @@ -1118,7 +1167,6 @@ Raven.prototype = {

_processException: function(type, message, fileurl, lineno, frames, options) {
var stacktrace;

if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;

message += '';
Expand Down
27 changes: 26 additions & 1 deletion test/raven.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,9 @@ describe('Raven (public API)', function() {
Raven.context({foo: 'bar'}, broken);
}, error);
assert.isTrue(Raven.captureException.called);
assert.deepEqual(Raven.captureException.lastCall.args, [error, {'foo': 'bar'}]);
assert.deepEqual(Raven.captureException.lastCall.args, [error, {
'foo': 'bar'
}]);
});

it('should capture the exception without options', function() {
Expand Down Expand Up @@ -2022,6 +2024,29 @@ describe('Raven (public API)', function() {
});
});

it('should include a synthetic stacktrace if stacktrace:true is passed', function () {
this.sinon.stub(Raven, 'isSetup').returns(true);
this.sinon.stub(Raven, '_send');

function foo() {
Raven.captureMessage('foo', {
stacktrace: true
});
}

foo();
var frames = Raven._send.lastCall.args[0].stacktrace.frames;

// Raven.captureMessage
var last = frames[frames.length - 1];
assert.isTrue(/(captureMessage|^\?)$/.test(last.function)); // loose equality check because differs per-browser
assert.equal(last.in_app, false);

// foo
var secondLast = frames[frames.length - 2];
assert.equal(secondLast.function, 'foo');
assert.equal(secondLast.in_app, true);
});
});

describe('.captureException', function() {
Expand Down

0 comments on commit e8040b1

Please sign in to comment.