Skip to content

Commit 79084f2

Browse files
committed
Mostly working
1 parent a0792da commit 79084f2

17 files changed

+218
-107
lines changed

packages/browser/src/backend.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BaseBackend, getEnvelopeEndpointWithUrlEncodedAuth, initAPIDetails } from '@sentry/core';
22
import { Event, EventHint, Options, Severity, Transport, TransportOptions } from '@sentry/types';
3-
import { supportsFetch } from '@sentry/utils';
3+
import { StackLineParser, StackParser, stackParserFromOptions, supportsFetch } from '@sentry/utils';
44

55
import { eventFromException, eventFromMessage } from './eventbuilder';
66
import { FetchTransport, makeNewFetchTransport, makeNewXHRTransport, XHRTransport } from './transports';
@@ -23,6 +23,12 @@ export interface BrowserOptions extends Options {
2323
* By default, all errors will be sent.
2424
*/
2525
denyUrls?: Array<string | RegExp>;
26+
27+
/**
28+
* A stack parser implementation or an array of stack line parsers
29+
* By default, a stack parser is supplied for all supported browsers
30+
*/
31+
stackParser?: StackParser | StackLineParser[];
2632
}
2733

2834
/**
@@ -34,13 +40,19 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
3440
* @inheritDoc
3541
*/
3642
public eventFromException(exception: unknown, hint?: EventHint): PromiseLike<Event> {
37-
return eventFromException(exception, hint, this._options.attachStacktrace);
43+
return eventFromException(stackParserFromOptions(this._options), exception, hint, this._options.attachStacktrace);
3844
}
3945
/**
4046
* @inheritDoc
4147
*/
4248
public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): PromiseLike<Event> {
43-
return eventFromMessage(message, level, hint, this._options.attachStacktrace);
49+
return eventFromMessage(
50+
stackParserFromOptions(this._options),
51+
message,
52+
level,
53+
hint,
54+
this._options.attachStacktrace,
55+
);
4456
}
4557

4658
/**

packages/browser/src/eventbuilder.ts

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Event, EventHint, Exception, Severity, StackFrame } from '@sentry/types
22
import {
33
addExceptionMechanism,
44
addExceptionTypeValue,
5-
createStackParser,
65
extractExceptionKeysForMessage,
76
isDOMError,
87
isDOMException,
@@ -12,24 +11,15 @@ import {
1211
isPlainObject,
1312
normalizeToSize,
1413
resolvedSyncPromise,
14+
StackParser,
1515
} from '@sentry/utils';
1616

17-
import {
18-
chromeStackParser,
19-
geckoStackParser,
20-
opera10StackParser,
21-
opera11StackParser,
22-
winjsStackParser,
23-
} from './stack-parsers';
24-
2517
/**
2618
* This function creates an exception from an TraceKitStackTrace
27-
* @param stacktrace TraceKitStackTrace that will be converted to an exception
28-
* @hidden
2919
*/
30-
export function exceptionFromError(ex: Error): Exception {
20+
export function exceptionFromError(stackParser: StackParser, ex: Error): Exception {
3121
// Get the frames first since Opera can lose the stack if we touch anything else first
32-
const frames = parseStackFrames(ex);
22+
const frames = parseStackFrames(stackParser, ex);
3323

3424
const exception: Exception = {
3525
type: ex && ex.name,
@@ -51,6 +41,7 @@ export function exceptionFromError(ex: Error): Exception {
5141
* @hidden
5242
*/
5343
export function eventFromPlainObject(
44+
stackParser: StackParser,
5445
exception: Record<string, unknown>,
5546
syntheticException?: Error,
5647
isUnhandledRejection?: boolean,
@@ -72,7 +63,7 @@ export function eventFromPlainObject(
7263
};
7364

7465
if (syntheticException) {
75-
const frames = parseStackFrames(syntheticException);
66+
const frames = parseStackFrames(stackParser, syntheticException);
7667
if (frames.length) {
7768
event.stacktrace = { frames };
7869
}
@@ -84,16 +75,19 @@ export function eventFromPlainObject(
8475
/**
8576
* @hidden
8677
*/
87-
export function eventFromError(ex: Error): Event {
78+
export function eventFromError(stackParser: StackParser, ex: Error): Event {
8879
return {
8980
exception: {
90-
values: [exceptionFromError(ex)],
81+
values: [exceptionFromError(stackParser, ex)],
9182
},
9283
};
9384
}
9485

9586
/** Parses stack frames from an error */
96-
export function parseStackFrames(ex: Error & { framesToPop?: number; stacktrace?: string }): StackFrame[] {
87+
export function parseStackFrames(
88+
stackParser: StackParser,
89+
ex: Error & { framesToPop?: number; stacktrace?: string },
90+
): StackFrame[] {
9791
// Access and store the stacktrace property before doing ANYTHING
9892
// else to it because Opera is not very good at providing it
9993
// reliably in other circumstances.
@@ -102,13 +96,7 @@ export function parseStackFrames(ex: Error & { framesToPop?: number; stacktrace?
10296
const popSize = getPopSize(ex);
10397

10498
try {
105-
return createStackParser(
106-
opera10StackParser,
107-
opera11StackParser,
108-
chromeStackParser,
109-
winjsStackParser,
110-
geckoStackParser,
111-
)(stacktrace, popSize);
99+
return stackParser(stacktrace, popSize);
112100
} catch (e) {
113101
// no-empty
114102
}
@@ -154,12 +142,13 @@ function extractMessage(ex: Error & { message: { error?: Error } }): string {
154142
* @hidden
155143
*/
156144
export function eventFromException(
145+
stackParser: StackParser,
157146
exception: unknown,
158147
hint?: EventHint,
159148
attachStacktrace?: boolean,
160149
): PromiseLike<Event> {
161150
const syntheticException = (hint && hint.syntheticException) || undefined;
162-
const event = eventFromUnknownInput(exception, syntheticException, attachStacktrace);
151+
const event = eventFromUnknownInput(stackParser, exception, syntheticException, attachStacktrace);
163152
addExceptionMechanism(event); // defaults to { type: 'generic', handled: true }
164153
event.level = Severity.Error;
165154
if (hint && hint.event_id) {
@@ -173,13 +162,14 @@ export function eventFromException(
173162
* @hidden
174163
*/
175164
export function eventFromMessage(
165+
stackParser: StackParser,
176166
message: string,
177167
level: Severity = Severity.Info,
178168
hint?: EventHint,
179169
attachStacktrace?: boolean,
180170
): PromiseLike<Event> {
181171
const syntheticException = (hint && hint.syntheticException) || undefined;
182-
const event = eventFromString(message, syntheticException, attachStacktrace);
172+
const event = eventFromString(stackParser, message, syntheticException, attachStacktrace);
183173
event.level = level;
184174
if (hint && hint.event_id) {
185175
event.event_id = hint.event_id;
@@ -191,6 +181,7 @@ export function eventFromMessage(
191181
* @hidden
192182
*/
193183
export function eventFromUnknownInput(
184+
stackParser: StackParser,
194185
exception: unknown,
195186
syntheticException?: Error,
196187
attachStacktrace?: boolean,
@@ -201,7 +192,7 @@ export function eventFromUnknownInput(
201192
if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
202193
// If it is an ErrorEvent with `error` property, extract it to get actual Error
203194
const errorEvent = exception as ErrorEvent;
204-
return eventFromError(errorEvent.error as Error);
195+
return eventFromError(stackParser, errorEvent.error as Error);
205196
}
206197

207198
// If it is a `DOMError` (which is a legacy API, but still supported in some browsers) then we just extract the name
@@ -215,11 +206,11 @@ export function eventFromUnknownInput(
215206
const domException = exception as DOMException;
216207

217208
if ('stack' in (exception as Error)) {
218-
event = eventFromError(exception as Error);
209+
event = eventFromError(stackParser, exception as Error);
219210
} else {
220211
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
221212
const message = domException.message ? `${name}: ${domException.message}` : name;
222-
event = eventFromString(message, syntheticException, attachStacktrace);
213+
event = eventFromString(stackParser, message, syntheticException, attachStacktrace);
223214
addExceptionTypeValue(event, message);
224215
}
225216
if ('code' in domException) {
@@ -230,14 +221,14 @@ export function eventFromUnknownInput(
230221
}
231222
if (isError(exception)) {
232223
// we have a real Error object, do nothing
233-
return eventFromError(exception);
224+
return eventFromError(stackParser, exception);
234225
}
235226
if (isPlainObject(exception) || isEvent(exception)) {
236227
// If it's a plain object or an instance of `Event` (the built-in JS kind, not this SDK's `Event` type), serialize
237228
// it manually. This will allow us to group events based on top-level keys which is much better than creating a new
238229
// group on any key/value change.
239230
const objectException = exception as Record<string, unknown>;
240-
event = eventFromPlainObject(objectException, syntheticException, isUnhandledRejection);
231+
event = eventFromPlainObject(stackParser, objectException, syntheticException, isUnhandledRejection);
241232
addExceptionMechanism(event, {
242233
synthetic: true,
243234
});
@@ -253,7 +244,7 @@ export function eventFromUnknownInput(
253244
// - a plain Object
254245
//
255246
// So bail out and capture it as a simple message:
256-
event = eventFromString(exception as string, syntheticException, attachStacktrace);
247+
event = eventFromString(stackParser, exception as string, syntheticException, attachStacktrace);
257248
addExceptionTypeValue(event, `${exception}`, undefined);
258249
addExceptionMechanism(event, {
259250
synthetic: true,
@@ -265,13 +256,18 @@ export function eventFromUnknownInput(
265256
/**
266257
* @hidden
267258
*/
268-
export function eventFromString(input: string, syntheticException?: Error, attachStacktrace?: boolean): Event {
259+
export function eventFromString(
260+
stackParser: StackParser,
261+
input: string,
262+
syntheticException?: Error,
263+
attachStacktrace?: boolean,
264+
): Event {
269265
const event: Event = {
270266
message: input,
271267
};
272268

273269
if (attachStacktrace && syntheticException) {
274-
const frames = parseStackFrames(syntheticException);
270+
const frames = parseStackFrames(stackParser, syntheticException);
275271
if (frames.length) {
276272
event.stacktrace = { frames };
277273
}

packages/browser/src/exports.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ export {
4141
withScope,
4242
} from '@sentry/core';
4343

44+
export {
45+
defaultStackParsers,
46+
chromeStackParser,
47+
geckoStackParser,
48+
opera10StackParser,
49+
opera11StackParser,
50+
winjsStackParser,
51+
} from './stack-parsers';
52+
4453
export { BrowserOptions } from './backend';
4554
export { BrowserClient } from './client';
4655
export { injectReportDialog, ReportDialogOptions } from './helpers';

packages/browser/src/integrations/globalhandlers.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import {
99
isPrimitive,
1010
isString,
1111
logger,
12+
StackParser,
13+
stackParserFromOptions,
1214
} from '@sentry/utils';
1315

16+
import { BrowserClient } from '../client';
1417
import { eventFromUnknownInput } from '../eventbuilder';
1518
import { IS_DEBUG_BUILD } from '../flags';
1619
import { shouldIgnoreOnError } from '../helpers';
@@ -79,7 +82,7 @@ function _installGlobalOnErrorHandler(): void {
7982
'error',
8083
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8184
(data: { msg: any; url: any; line: any; column: any; error: any }) => {
82-
const [hub, attachStacktrace] = getHubAndAttachStacktrace();
85+
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
8386
if (!hub.getIntegration(GlobalHandlers)) {
8487
return;
8588
}
@@ -92,7 +95,7 @@ function _installGlobalOnErrorHandler(): void {
9295
error === undefined && isString(msg)
9396
? _eventFromIncompleteOnError(msg, url, line, column)
9497
: _enhanceEventWithInitialFrame(
95-
eventFromUnknownInput(error || msg, undefined, attachStacktrace, false),
98+
eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false),
9699
url,
97100
line,
98101
column,
@@ -111,7 +114,7 @@ function _installGlobalOnUnhandledRejectionHandler(): void {
111114
'unhandledrejection',
112115
// eslint-disable-next-line @typescript-eslint/no-explicit-any
113116
(e: any) => {
114-
const [hub, attachStacktrace] = getHubAndAttachStacktrace();
117+
const [hub, stackParser, attachStacktrace] = getHubAndOptions();
115118
if (!hub.getIntegration(GlobalHandlers)) {
116119
return;
117120
}
@@ -142,7 +145,7 @@ function _installGlobalOnUnhandledRejectionHandler(): void {
142145

143146
const event = isPrimitive(error)
144147
? _eventFromRejectionWithPrimitive(error)
145-
: eventFromUnknownInput(error, undefined, attachStacktrace, true);
148+
: eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true);
146149

147150
event.level = Severity.Error;
148151

@@ -250,9 +253,11 @@ function addMechanismAndCapture(hub: Hub, error: EventHint['originalException'],
250253
});
251254
}
252255

253-
function getHubAndAttachStacktrace(): [Hub, boolean | undefined] {
256+
function getHubAndOptions(): [Hub, StackParser, boolean | undefined] {
254257
const hub = getCurrentHub();
255-
const client = hub.getClient();
256-
const attachStacktrace = client && client.getOptions().attachStacktrace;
257-
return [hub, attachStacktrace];
258+
const client = hub.getClient<BrowserClient>();
259+
const options = client?.getOptions();
260+
const parser = stackParserFromOptions(options);
261+
const attachStacktrace = options?.attachStacktrace;
262+
return [hub, parser, attachStacktrace];
258263
}

packages/browser/src/integrations/linkederrors.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
22
import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types';
3-
import { isInstanceOf } from '@sentry/utils';
3+
import { isInstanceOf, StackParser, stackParserFromOptions } from '@sentry/utils';
44

5+
import { BrowserClient } from '../client';
56
import { exceptionFromError } from '../eventbuilder';
67

78
const DEFAULT_KEY = 'cause';
@@ -46,32 +47,47 @@ export class LinkedErrors implements Integration {
4647
* @inheritDoc
4748
*/
4849
public setupOnce(): void {
50+
const options = getCurrentHub().getClient<BrowserClient>()?.getOptions();
51+
const parser = stackParserFromOptions(options);
52+
4953
addGlobalEventProcessor((event: Event, hint?: EventHint) => {
5054
const self = getCurrentHub().getIntegration(LinkedErrors);
51-
return self ? _handler(self._key, self._limit, event, hint) : event;
55+
return self ? _handler(parser, self._key, self._limit, event, hint) : event;
5256
});
5357
}
5458
}
5559

5660
/**
5761
* @inheritDoc
5862
*/
59-
export function _handler(key: string, limit: number, event: Event, hint?: EventHint): Event | null {
63+
export function _handler(
64+
parser: StackParser,
65+
key: string,
66+
limit: number,
67+
event: Event,
68+
hint?: EventHint,
69+
): Event | null {
6070
if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
6171
return event;
6272
}
63-
const linkedErrors = _walkErrorTree(limit, hint.originalException as ExtendedError, key);
73+
const linkedErrors = _walkErrorTree(parser, limit, hint.originalException as ExtendedError, key);
6474
event.exception.values = [...linkedErrors, ...event.exception.values];
6575
return event;
6676
}
6777

6878
/**
6979
* JSDOC
7080
*/
71-
export function _walkErrorTree(limit: number, error: ExtendedError, key: string, stack: Exception[] = []): Exception[] {
81+
export function _walkErrorTree(
82+
parser: StackParser,
83+
limit: number,
84+
error: ExtendedError,
85+
key: string,
86+
stack: Exception[] = [],
87+
): Exception[] {
7288
if (!isInstanceOf(error[key], Error) || stack.length + 1 >= limit) {
7389
return stack;
7490
}
75-
const exception = exceptionFromError(error[key]);
76-
return _walkErrorTree(limit, error[key], key, [exception, ...stack]);
91+
const exception = exceptionFromError(parser, error[key]);
92+
return _walkErrorTree(parser, limit, error[key], key, [exception, ...stack]);
7793
}

0 commit comments

Comments
 (0)