Skip to content

Commit 90ba247

Browse files
authored
feat: Send exception mechanisms (#1335)
* feat: initial mechanism implementation * feat(mechanism): Update mechanism to latest spec * ref: Review changes
1 parent a010f2e commit 90ba247

File tree

2 files changed

+149
-46
lines changed

2 files changed

+149
-46
lines changed

src/raven.js

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ function now() {
4949
var _window =
5050
typeof window !== 'undefined'
5151
? window
52-
: typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
52+
: typeof global !== 'undefined'
53+
? global
54+
: typeof self !== 'undefined'
55+
? self
56+
: {};
5357
var _document = _window.document;
5458
var _navigator = _window.navigator;
5559

@@ -305,7 +309,7 @@ Raven.prototype = {
305309
if (isFunction(options)) {
306310
args = func || [];
307311
func = options;
308-
options = undefined;
312+
options = {};
309313
}
310314

311315
return this.wrap(options, func).apply(this, args);
@@ -429,8 +433,9 @@ Raven.prototype = {
429433
_promiseRejectionHandler: function(event) {
430434
this._logDebug('debug', 'Raven caught unhandled promise rejection:', event);
431435
this.captureException(event.reason, {
432-
extra: {
433-
unhandledPromiseRejection: true
436+
mechanism: {
437+
type: 'onunhandledrejection',
438+
handled: false
434439
}
435440
});
436441
},
@@ -1107,7 +1112,15 @@ Raven.prototype = {
11071112
}
11081113
var originalCallback = args[0];
11091114
if (isFunction(originalCallback)) {
1110-
args[0] = self.wrap(originalCallback);
1115+
args[0] = self.wrap(
1116+
{
1117+
mechanism: {
1118+
type: 'instrument',
1119+
data: {function: orig.name}
1120+
}
1121+
},
1122+
originalCallback
1123+
);
11111124
}
11121125

11131126
// IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
@@ -1134,7 +1147,15 @@ Raven.prototype = {
11341147
// preserve arity
11351148
try {
11361149
if (fn && fn.handleEvent) {
1137-
fn.handleEvent = self.wrap(fn.handleEvent);
1150+
fn.handleEvent = self.wrap(
1151+
{
1152+
mechanism: {
1153+
type: 'instrument',
1154+
data: {target: global, function: 'handleEvent', handler: fn.name}
1155+
}
1156+
},
1157+
fn.handleEvent
1158+
);
11381159
}
11391160
} catch (err) {
11401161
// can sometimes get 'Permission denied to access property "handle Event'
@@ -1174,7 +1195,20 @@ Raven.prototype = {
11741195
return orig.call(
11751196
this,
11761197
evtName,
1177-
self.wrap(fn, undefined, before),
1198+
self.wrap(
1199+
{
1200+
mechanism: {
1201+
type: 'instrument',
1202+
data: {
1203+
target: global,
1204+
function: 'addEventListener',
1205+
handler: fn.name
1206+
}
1207+
}
1208+
},
1209+
fn,
1210+
before
1211+
),
11781212
capture,
11791213
secure
11801214
);
@@ -1208,7 +1242,17 @@ Raven.prototype = {
12081242
'requestAnimationFrame',
12091243
function(orig) {
12101244
return function(cb) {
1211-
return orig(self.wrap(cb));
1245+
return orig(
1246+
self.wrap(
1247+
{
1248+
mechanism: {
1249+
type: 'instrument',
1250+
data: {function: 'requestAnimationFrame', handler: orig.name}
1251+
}
1252+
},
1253+
cb
1254+
)
1255+
);
12121256
};
12131257
},
12141258
wrappedBuiltIns
@@ -1271,7 +1315,15 @@ Raven.prototype = {
12711315
function wrapProp(prop, xhr) {
12721316
if (prop in xhr && isFunction(xhr[prop])) {
12731317
fill(xhr, prop, function(orig) {
1274-
return self.wrap(orig);
1318+
return self.wrap(
1319+
{
1320+
mechanism: {
1321+
type: 'instrument',
1322+
data: {function: prop, handler: orig.name}
1323+
}
1324+
},
1325+
orig
1326+
);
12751327
}); // intentionally don't track filled methods on XHR instances
12761328
}
12771329
}
@@ -1336,7 +1388,19 @@ Raven.prototype = {
13361388
xhr,
13371389
'onreadystatechange',
13381390
function(orig) {
1339-
return self.wrap(orig, undefined, onreadystatechangeHandler);
1391+
return self.wrap(
1392+
{
1393+
mechanism: {
1394+
type: 'instrument',
1395+
data: {
1396+
function: 'onreadystatechange',
1397+
handler: orig.name
1398+
}
1399+
}
1400+
},
1401+
orig,
1402+
onreadystatechangeHandler
1403+
);
13401404
} /* intentionally don't track this instrumentation */
13411405
);
13421406
} else {
@@ -1560,10 +1624,16 @@ Raven.prototype = {
15601624
return globalServer;
15611625
},
15621626

1563-
_handleOnErrorStackInfo: function() {
1627+
_handleOnErrorStackInfo: function(stackInfo, options) {
1628+
options = options || {};
1629+
options.mechanism = options.mechanism || {
1630+
type: 'onerror',
1631+
handled: false
1632+
};
1633+
15641634
// if we are intentionally ignoring errors via onerror, bail out
15651635
if (!this._ignoreOnError) {
1566-
this._handleStackInfo.apply(this, arguments);
1636+
this._handleStackInfo(stackInfo, options);
15671637
}
15681638
},
15691639

@@ -1700,6 +1770,19 @@ Raven.prototype = {
17001770
options
17011771
);
17021772

1773+
// Move mechanism from options to exception interface
1774+
// We do this, as requiring user to pass `{exception:{mechanism:{ ... }}}` would be
1775+
// too much
1776+
if (!data.exception.mechanism && data.mechanism) {
1777+
data.exception.mechanism = data.mechanism;
1778+
delete data.mechanism;
1779+
}
1780+
1781+
data.exception.mechanism = objectMerge(data.exception.mechanism || {}, {
1782+
type: 'generic',
1783+
handled: true
1784+
});
1785+
17031786
// Fire away!
17041787
this._send(data);
17051788
},

test/raven.test.js

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ describe('globals', function() {
633633
'http://example.com/override.js',
634634
10,
635635
frames.slice(0),
636-
{}
636+
{mechanism: {}}
637637
);
638638
assert.deepEqual(Raven._send.lastCall.args, [
639639
{
@@ -646,13 +646,17 @@ describe('globals', function() {
646646
frames: framesFlipped
647647
}
648648
}
649-
]
649+
],
650+
mechanism: {
651+
type: 'generic',
652+
handled: true
653+
}
650654
},
651655
transaction: 'http://example.com/file1.js'
652656
}
653657
]);
654658

655-
Raven._processException('Error', 'lol', '', 10, frames.slice(0), {});
659+
Raven._processException('Error', 'lol', '', 10, frames.slice(0), {mechanism: {}});
656660
assert.deepEqual(Raven._send.lastCall.args, [
657661
{
658662
exception: {
@@ -664,14 +668,19 @@ describe('globals', function() {
664668
frames: framesFlipped
665669
}
666670
}
667-
]
671+
],
672+
mechanism: {
673+
type: 'generic',
674+
handled: true
675+
}
668676
},
669677
transaction: 'http://example.com/file1.js'
670678
}
671679
]);
672680

673681
Raven._processException('Error', 'lol', '', 10, frames.slice(0), {
674-
extra: 'awesome'
682+
extra: 'awesome',
683+
mechanism: {}
675684
});
676685
assert.deepEqual(Raven._send.lastCall.args, [
677686
{
@@ -684,7 +693,11 @@ describe('globals', function() {
684693
frames: framesFlipped
685694
}
686695
}
687-
]
696+
],
697+
mechanism: {
698+
type: 'generic',
699+
handled: true
700+
}
688701
},
689702
transaction: 'http://example.com/file1.js',
690703
extra: 'awesome'
@@ -695,14 +708,9 @@ describe('globals', function() {
695708
it('should send a proper payload without frames', function() {
696709
this.sinon.stub(Raven, '_send');
697710

698-
Raven._processException(
699-
'Error',
700-
'lol',
701-
'http://example.com/override.js',
702-
10,
703-
[],
704-
{}
705-
);
711+
Raven._processException('Error', 'lol', 'http://example.com/override.js', 10, [], {
712+
mechanism: {}
713+
});
706714
assert.deepEqual(Raven._send.lastCall.args, [
707715
{
708716
exception: {
@@ -720,20 +728,19 @@ describe('globals', function() {
720728
]
721729
}
722730
}
723-
]
731+
],
732+
mechanism: {
733+
type: 'generic',
734+
handled: true
735+
}
724736
},
725737
transaction: 'http://example.com/override.js'
726738
}
727739
]);
728740

729-
Raven._processException(
730-
'Error',
731-
'lol',
732-
'http://example.com/override.js',
733-
10,
734-
[],
735-
{}
736-
);
741+
Raven._processException('Error', 'lol', 'http://example.com/override.js', 10, [], {
742+
mechanism: {}
743+
});
737744
assert.deepEqual(Raven._send.lastCall.args, [
738745
{
739746
exception: {
@@ -751,14 +758,19 @@ describe('globals', function() {
751758
]
752759
}
753760
}
754-
]
761+
],
762+
mechanism: {
763+
type: 'generic',
764+
handled: true
765+
}
755766
},
756767
transaction: 'http://example.com/override.js'
757768
}
758769
]);
759770

760771
Raven._processException('Error', 'lol', 'http://example.com/override.js', 10, [], {
761-
extra: 'awesome'
772+
extra: 'awesome',
773+
mechanism: {}
762774
});
763775
assert.deepEqual(Raven._send.lastCall.args, [
764776
{
@@ -777,7 +789,11 @@ describe('globals', function() {
777789
]
778790
}
779791
}
780-
]
792+
],
793+
mechanism: {
794+
type: 'generic',
795+
handled: true
796+
}
781797
},
782798
transaction: 'http://example.com/override.js',
783799
extra: 'awesome'
@@ -1980,7 +1996,16 @@ describe('globals', function() {
19801996
Raven._handleOnErrorStackInfo(stackInfo, {foo: 'bar'});
19811997

19821998
assert.equal(Raven._handleStackInfo.callCount, 1);
1983-
assert.deepEqual(Raven._handleStackInfo.lastCall.args, [stackInfo, {foo: 'bar'}]);
1999+
assert.deepEqual(Raven._handleStackInfo.lastCall.args, [
2000+
stackInfo,
2001+
{
2002+
foo: 'bar',
2003+
mechanism: {
2004+
type: 'onerror',
2005+
handled: false
2006+
}
2007+
}
2008+
]);
19842009
});
19852010
});
19862011

@@ -2655,12 +2680,7 @@ describe('Raven (public API)', function() {
26552680
Raven.context({foo: 'bar'}, broken);
26562681
}, error);
26572682
assert.isTrue(Raven.captureException.called);
2658-
assert.deepEqual(Raven.captureException.lastCall.args, [
2659-
error,
2660-
{
2661-
foo: 'bar'
2662-
}
2663-
]);
2683+
assert.deepEqual(Raven.captureException.lastCall.args, [error, {foo: 'bar'}]);
26642684
});
26652685

26662686
it('should capture the exception without options', function() {
@@ -2673,7 +2693,7 @@ describe('Raven (public API)', function() {
26732693
Raven.context(broken);
26742694
}, error);
26752695
assert.isTrue(Raven.captureException.called);
2676-
assert.deepEqual(Raven.captureException.lastCall.args, [error, undefined]);
2696+
assert.deepEqual(Raven.captureException.lastCall.args, [error, {}]);
26772697
});
26782698

26792699
it('should execute the callback without arguments', function() {

0 commit comments

Comments
 (0)