8000 fix: Exception type/value, Loader promise reject (#1838) · DanielGibbsNZ/sentry-javascript@afe627e · GitHub
[go: up one dir, main page]

Skip to content

Commit afe627e

Browse files
authored
fix: Exception type/value, Loader promise reject (getsentry#1838)
* fix: Exception type/value, Loader promise reject * fix: Comment * revert: Changes to utils * fix: Code Review
1 parent fec30bc commit afe627e

File tree

6 files changed

+103
-17
lines changed

6 files changed

+103
-17
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## Unreleased
44

5+
## 4.5.2
6+
7+
- [browser] fix: <unlabeled> event for unhandledRejection
8+
- [loader] fix: Handle unhandledRejection the same way as it would be thrown
9+
510
## 4.5.1
611

712
- [utils] fix: Don't npm ignore esm for utils

packages/browser/src/integrations/globalhandlers.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getCurrentHub } from '@sentry/core';
22
import { Integration, SentryEvent } from '@sentry/types';
33
import { logger } from '@sentry/utils/logger';
4-
import { eventFromStacktrace } from '../parsers';
4+
import { addExceptionTypeValue, eventFromStacktrace } from '../parsers';
55
import {
66
installGlobalHandler,
77
installGlobalUnhandledRejectionHandler,
@@ -78,21 +78,44 @@ export class GlobalHandlers implements Integration {
7878
}
7979
}
8080

81-
/** JSDoc */
81+
/**
82+
* This function creates an SentryEvent from an TraceKitStackTrace.
83+
*
84+
* @param stacktrace TraceKitStackTrace to be converted to an SentryEvent.
85+
*/
8286
private eventFromGlobalHandler(stacktrace: TraceKitStackTrace): SentryEvent {
8387
const event = eventFromStacktrace(stacktrace);
84-
return {
88+
89+
const data: { [key: string]: string } = {
90+
mode: stacktrace.mode,
91+
};
92+
93+
if (stacktrace.message) {
94+
data.message = stacktrace.message;
95+
}
96+
97+
if (stacktrace.name) {
98+
data.name = stacktrace.name;
99+
}
100+
101+
const newEvent: SentryEvent = {
85102
...event,
86103
exception: {
87104
...event.exception,
88105
mechanism: {
89-
data: {
90-
mode: stacktrace.mode,
91-
},
106+
data,
92107
handled: false,
93108
type: stacktrace.mechanism,
94109
},
95110
},
96111
};
112+
113+
const fallbackValue = typeof stacktrace.original !== 'undefined' ? `${stacktrace.original}` : '';
114+
const fallbackType = stacktrace.mechanism === 'onunhandledrejection' ? 'UnhandledRejection' : 'Error';
115+
116+
// This makes sure we have type/value in every exception
117+
addExceptionTypeValue(newEvent, fallbackValue, fallbackType);
118+
119+
return newEvent;
97120
}
98121
}

packages/browser/src/loader.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,14 @@
128128
// Because we installed the SDK, at this point we have an access to TraceKit's handler,
129129
// which can take care of browser differences (eg. missing exception argument in onerror)
130130
var tracekitErrorHandler = _window[_onerror];
131+
var tracekitUnhandledRejectionHandler = _window[_onunhandledrejection];
131132

132133
// And now capture all previously caught exceptions
133134
for (var i = 0; i < data.length; i++) {
134-
if (data[i].e) {
135+
if (data[i].e && tracekitErrorHandler) {
135136
tracekitErrorHandler.apply(_window, data[i].e);
136-
} else if (data[i].p) {
137-
SDK.captureException(data[i].p);
137+
} else if (data[i].p && tracekitUnhandledRejectionHandler) {
138+
tracekitUnhandledRejectionHandler.apply(_window, [data[i].p]);
138139
}
139140
}
140141
} catch (o_O) {

packages/browser/src/parsers.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@ import { computeStackTrace, StackFrame as TraceKitStackFrame, StackTrace as Trac
66

77
const STACKTRACE_LIMIT = 50;
88

9-
/** JSDoc */
9+
/**
10+
* This function creates an exception from an TraceKitStackTrace
11+
* @param stacktrace TraceKitStackTrace that will be converted to an exception
12+
*/
1013
export function exceptionFromStacktrace(stacktrace: TraceKitStackTrace): SentryException {
1114
const frames = prepareFramesForEvent(stacktrace.stack);
1215

13-
const exception = {
14-
stacktrace: { frames },
16+
const exception: SentryException = {
1517
type: stacktrace.name,
1618
value: stacktrace.message,
1719
};
1820

21+
if (frames && frames.length) {
22+
exception.stacktrace = { frames };
23+
}
24+
1925
// tslint:disable-next-line:strict-type-predicates
2026
if (exception.type === undefined && exception.value === '') {
2127
exception.value = 'Unrecoverable error caught';
@@ -96,12 +102,13 @@ export function prepareFramesForEvent(stack: TraceKitStackFrame[]): StackFrame[]
96102
/**
97103
* Adds exception values, type and value to an synthetic Exception.
98104
* @param event The event to modify.
99-
* @param message Message to be added.
105+
* @param value Value of the exception.
106+
* @param type Type of the exception.
100107
*/
101-
export function addExceptionTypeValue(event: SentryEvent, message: string): void {
108+
export function addExceptionTypeValue(event: SentryEvent, value?: string, type?: string): void {
102109
event.exception = event.exception || {};
103110
event.exception.values = event.exception.values || [];
104111
event.exception.values[0] = event.exception.values[0] || {};
105-
event.exception.values[0].value = event.exception.values[0].value || message;
106-
event.exception.values[0].type = event.exception.values[0].type || 'Error';
112+
event.exception.values[0].value = event.exception.values[0].value || value || '';
113+
event.exception.values[0].type = event.exception.values[0].type || type || 'Error';
107114
}

packages/browser/src/tracekit.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface StackTrace {
2323
url: string;
2424
stack: StackFrame[];
2525
useragent: string;
26+
original?: string;
2627
}
2728

2829
interface ComputeStackTrace {
@@ -1468,6 +1469,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
14681469
}
14691470

14701471
return {
1472+
original: ex,
14711473
name: ex.name,
14721474
message: ex.message,
14731475
mode: 'failed',

packages/browser/test/integration/test.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ for (var idx in frames) {
466466
function(sentryData) {
467467
if (debounceAssertEventCount(sentryData, 1, done)) {
468468
var sentryData = sentryData[0];
469-
assert.equal(sentryData.exception.values[0].type, undefined);
469+
assert.equal(sentryData.exception.values[0].type, 'Error');
470470

471471
// #<Object> is covering default Android 4.4 and 5.1 browser
472472
assert.match(sentryData.exception.values[0].value, /^(\[object Object\]|#<Object>)$/);
@@ -617,6 +617,54 @@ for (var idx in frames) {
617617
);
618618
});
619619

620+
it('should capture unhandledrejection with error', function(done) {
621+
var iframe = this.iframe;
622+
623+
iframeExecute(
624+
iframe,
625+
done,
626+
function() {
627+
setTimeout(function() {
628+
return Promise.reject(new Error('test2'));
629+
});
630+
},
631+
function(sentryData) {
632+
if (debounceAssertEventCount(sentryData, 1, done)) {
633+
assert.equal(sentryData[0].exception.values[0].value, 'test2');
634+
assert.equal(sentryData[0].exception.values[0].type, 'Error');
635+
assert.isAtLeast(sentryData[0].exception.values[0].stacktrace.frames.length, 1);
636+
assert.equal(sentryData[0].exception.mechanism.handled, false);
637+
assert.equal(sentryData[0].exception.mechanism.type, 'onunhandledrejection');
638+
done();
639+
}
640+
}
641+
);
642+
});
643+
644+
it('should capture unhandledrejection as string', function(done) {
645+
var iframe = this.iframe;
646+
647+
iframeExecute(
648+
iframe,
649+
done,
650+
function() {
651+
setTimeout(function() {
652+
return Promise.reject('test');
653+
});
654+
},
655+
function(sentryData) {
656+
if (debounceAssertEventCount(sentryData, 1, done)) {
657+
assert.equal(sentryData[0].exception.values[0].value, 'test');
658+
assert.equal(sentryData[0].exception.values[0].type, 'UnhandledRejection');
659+
assert.equal(sentryData[0].exception.values[0].stacktrace, undefined);
660+
assert.equal(sentryData[0].exception.mechanism.handled, false);
661+
assert.equal(sentryData[0].exception.mechanism.type, 'onunhandledrejection');
662+
done();
663+
}
664+
}
665+
);
666+
});
667+
620668
it('should capture exceptions inside setTimeout', function(done) {
621669
var iframe = this.iframe;
622670

0 commit comments

Comments
 (0)
0