Skip to content

Commit cd14def

Browse files
committed
ref: Major TraceKit and GlobalHandlers refactor
1 parent ea27f8e commit cd14def

File tree

17 files changed

+691
-1583
lines changed

17 files changed

+691
-1583
lines changed

packages/browser/src/backend.ts

+17-94
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
import { BaseBackend } from '@sentry/core';
22
import { Event, EventHint, Options, Severity, Transport } from '@sentry/types';
3-
import {
4-
addExceptionTypeValue,
5-
isDOMError,
6-
isDOMException,
7-
isError,
8-
isErrorEvent,
9-
isPlainObject,
10-
supportsFetch,
11-
SyncPromise,
12-
} from '@sentry/utils';
3+
import { addExceptionMechanism, supportsFetch, SyncPromise } from '@sentry/utils';
134

14-
import { eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
15-
import { _computeStackTrace } from './tracekit';
5+
import { eventFromString, eventFromUnknownInput } from './eventbuilder';
166
import { FetchTransport, XHRTransport } from './transports';
177

188
/**
@@ -67,95 +57,28 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
6757
* @inheritDoc
6858
*/
6959
public eventFromException(exception: any, hint?: EventHint): SyncPromise<Event> {
70-
let event: Event;
71-
72-
if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
73-
// If it is an ErrorEvent with `error` property, extract it to get actual Error
74-
const errorEvent = exception as ErrorEvent;
75-
exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
76-
event = eventFromStacktrace(_computeStackTrace(exception as Error));
77-
return SyncPromise.resolve(this._buildEvent(event, hint));
78-
}
79-
if (isDOMError(exception as DOMError) || isDOMException(exception as DOMException)) {
80-
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
81-
// then we just extract the name and message, as they don't provide anything else
82-
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
83-
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
84-
const domException = exception as DOMException;
85-
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
86-
const message = domException.message ? `${name}: ${domException.message}` : name;
87-
88-
return this.eventFromMessage(message, Severity.Error, hint).then(messageEvent => {
89-
addExceptionTypeValue(messageEvent, message);
90-
return SyncPromise.resolve(this._buildEvent(messageEvent, hint));
91-
});
92-
}
93-
if (isError(exception as Error)) {
94-
// we have a real Error object, do nothing
95-
event = eventFromStacktrace(_computeStackTrace(exception as Error));
96-
return SyncPromise.resolve(this._buildEvent(event, hint));
97-
}
98-
if (isPlainObject(exception as {}) && hint && hint.syntheticException) {
99-
// If it is plain Object, serialize it manually and extract options
100-
// This will allow us to group events based on top-level keys
101-
// which is much better than creating new group when any key/value change
102-
const objectException = exception as {};
103-
event = eventFromPlainObject(objectException, hint.syntheticException);
104-
addExceptionTypeValue(event, 'Custom Object', undefined, {
105-
handled: true,
106-
synthetic: true,
107-
type: 'generic',
108-
});
109-
event.level = Severity.Error;
110-
return SyncPromise.resolve(this._buildEvent(event, hint));
111-
}
112-
113-
// If none of previous checks were valid, then it means that
114-
// it's not a DOMError/DOMException
115-
// it's not a plain Object
116-
// it's not a valid ErrorEvent (one with an error property)
117-
// it's not an Error
118-
// So bail out and capture it as a simple message:
119-
const stringException = exception as string;
120-
return this.eventFromMessage(stringException, undefined, hint).then(messageEvent => {
121-
addExceptionTypeValue(messageEvent, `${stringException}`, undefined, {
122-
handled: true,
123-
synthetic: true,
124-
type: 'generic',
125-
});
126-
messageEvent.level = Severity.Error;
127-
return SyncPromise.resolve(this._buildEvent(messageEvent, hint));
60+
const syntheticException = (hint && hint.syntheticException) || undefined;
61+
const event = eventFromUnknownInput(exception, syntheticException);
62+
addExceptionMechanism(event, {
63+
handled: true,
64+
type: 'generic',
12865
});
66+
event.level = Severity.Error;
67+
if (hint && hint.event_id) {
68+
event.event_id = hint.event_id;
69+
}
70+
return SyncPromise.resolve(event);
12971
}
130-
131-
/**
132-
* This is an internal helper function that creates an event.
133-
*/
134-
private _buildEvent(event: Event, hint?: EventHint): Event {
135-
return {
136-
...event,
137-
event_id: hint && hint.event_id,
138-
};
139-
}
140-
14172
/**
14273
* @inheritDoc
14374
*/
14475
public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): SyncPromise<Event> {
145-
const event: Event = {
146-
event_id: hint && hint.event_id,
147-
level,
148-
message,
149-
};
150-
151-
if (this._options.attachStacktrace && hint && hint.syntheticException) {
152-
const stacktrace = _computeStackTrace(hint.syntheticException);
153-
const frames = prepareFramesForEvent(stacktrace.stack);
154-
event.stacktrace = {
155-
frames,
156-
};
76+
const syntheticException = (hint && hint.syntheticException) || undefined;
77+
const event = eventFromString(message, syntheticException);
78+
event.level = level;
79+
if (hint && hint.event_id) {
80+
event.event_id = hint.event_id;
15781
}
158-
15982
return SyncPromise.resolve(event);
16083
}
16184
}

packages/browser/src/eventbuilder.ts

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Event, Severity } from '@sentry/types';
2+
import {
3+
addExceptionMechanism,
4+
addExceptionTypeValue,
5+
isDOMError,
6+
isDOMException,
7+
isError,
8+
isErrorEvent,
9+
isPlainObject,
10+
} from '@sentry/utils';
11+
12+
import { eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
13+
import { computeStackTrace } from './tracekit';
14+
15+
/** JSDoc */
16+
export function eventFromUnknownInput(exception: unknown, syntheticException?: Error): Event {
17+
let event: Event;
18+
19+
if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
20+
// If it is an ErrorEvent with `error` property, extract it to get actual Error
21+
const errorEvent = exception as ErrorEvent;
22+
exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
23+
event = eventFromStacktrace(computeStackTrace(exception as Error));
24+
return event;
25+
}
26+
if (isDOMError(exception as DOMError) || isDOMException(exception as DOMException)) {
27+
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
28+
// then we just extract the name and message, as they don't provide anything else
29+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
30+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
31+
const domException = exception as DOMException;
32+
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
33+
const message = domException.message ? `${name}: ${domException.message}` : name;
34+
35+
event = eventFromString(message);
36+
addExceptionTypeValue(event, message);
37+
return event;
38+
}
39+
if (isError(exception as Error)) {
40+
// we have a real Error object, do nothing
41+
event = eventFromStacktrace(computeStackTrace(exception as Error));
42+
return event;
43+
}
44+
if (isPlainObject(exception as {})) {
45+
// If it is plain Object, serialize it manually and extract options
46+
// This will allow us to group events based on top-level keys
47+
// which is much better than creating new group when any key/value change
48+
const objectException = exception as {};
49+
event = eventFromPlainObject(objectException, syntheticException);
50+
addExceptionTypeValue(event, 'Custom Object', undefined);
51+
addExceptionMechanism(event, {
52+
synthetic: true,
53+
});
54+
event.level = Severity.Error;
55+
return event;
56+
}
57+
58+
// If none of previous checks were valid, then it means that
59+
// it's not a DOMError/DOMException
60+
// it's not a plain Object
61+
// it's not a valid ErrorEvent (one with an error property)
62+
// it's not an Error
63+
// So bail out and capture it as a simple message:
64+
event = eventFromString(exception as string, syntheticException);
65+
66+
addExceptionTypeValue(event, `${exception}`, undefined);
67+
addExceptionMechanism(event, {
68+
synthetic: true,
69+
});
70+
71+
return event;
72+
}
73+
74+
/** JSDoc */
75+
export function eventFromString(input: string, syntheticException?: Error): Event {
76+
const event: Event = {
77+
message: input,
78+
};
79+
80+
// TODO: Only if `this._options.attachStacktrace`
81+
if (syntheticException) {
82+
const stacktrace = computeStackTrace(syntheticException);
83+
const frames = prepareFramesForEvent(stacktrace.stack);
84+
event.stacktrace = {
85+
frames,
86+
};
87+
}
88+
89+
return event;
90+
}

packages/browser/src/helpers.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { captureException, getCurrentHub, withScope } from '@sentry/core';
22
import { Event as SentryEvent, Mechanism, WrappedFunction } from '@sentry/types';
3-
import { addExceptionTypeValue, isString, normalize } from '@sentry/utils';
3+
import { addExceptionMechanism, addExceptionTypeValue, isString, normalize } from '@sentry/utils';
44

55
const debounceDuration: number = 1000;
66
let keypressTimeout: number | undefined;
@@ -97,7 +97,8 @@ export function wrap(
9797
const processedEvent = { ...event };
9898

9999
if (options.mechanism) {
100-
addExceptionTypeValue(processedEvent, undefined, undefined, options.mechanism);
100+
addExceptionTypeValue(processedEvent, undefined, undefined);
101+
addExceptionMechanism(processedEvent, options.mechanism);
101102
}
102103

103104
processedEvent.extra = {

0 commit comments

Comments
 (0)