Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Native Linked Errors (RN Mixed stack traces) #3201

Merged
merged 20 commits into from
Aug 11, 2023
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 6 additions & 82 deletions src/js/integrations/nativelinkederrors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { exceptionFromError } from '@sentry/browser';
import type {
DebugImage,
Event,
Expand All @@ -24,7 +25,7 @@ interface LinkedErrorsOptions {
}

/**
*
* Processes JS and RN native linked errors.
*/
export class NativeLinkedErrors implements Integration {
marandaneto marked this conversation as resolved.
Show resolved Hide resolved
/**
Expand Down Expand Up @@ -68,7 +69,7 @@ export class NativeLinkedErrors implements Integration {
}

/**
*
* Enriches passed event with linked exceptions and native debug meta images.
*/
private async _handler(
parser: StackParser,
Expand Down Expand Up @@ -96,7 +97,8 @@ export class NativeLinkedErrors implements Integration {
}

/**
*
* Walks linked errors and created Sentry exceptions chain.
* Collects debug images from native errors stack frames.
*/
private async _walkErrorTree(
parser: StackParser,
Expand Down Expand Up @@ -144,7 +146,7 @@ export class NativeLinkedErrors implements Integration {
return this._walkErrorTree(
parser,
limit,
error[key],
linkedError,
key,
[...exceptions, exception],
[...debugImages, ...(exceptionDebugImages || [])],
Expand Down Expand Up @@ -227,81 +229,3 @@ export class NativeLinkedErrors implements Integration {
return NATIVE.fetchNativeStackFramesBy(instructionsAddr);
}
}

// TODO: Needs to be exported from @sentry/browser
marandaneto marked this conversation as resolved.
Show resolved Hide resolved
/**
* This function creates an exception from a JavaScript Error
*/
export function exceptionFromError(stackParser: StackParser, ex: Error): Exception {
// Get the frames first since Opera can lose the stack if we touch anything else first
const frames = parseStackFrames(stackParser, ex);

const exception: Exception = {
type: ex && ex.name,
value: extractMessage(ex),
};

if (frames.length) {
exception.stacktrace = { frames };
}

if (exception.type === undefined && exception.value === '') {
exception.value = 'Unrecoverable error caught';
}

return exception;
}

/** Parses stack frames from an error */
export function parseStackFrames(
stackParser: StackParser,
ex: Error & { framesToPop?: number; stacktrace?: string },
): StackFrame[] {
// Access and store the stacktrace property before doing ANYTHING
// else to it because Opera is not very good at providing it
// reliably in other circumstances.
const stacktrace = ex.stacktrace || ex.stack || '';

const popSize = getPopSize(ex);

try {
return stackParser(stacktrace, popSize);
} catch (e) {
// no-empty
}

return [];
}

/**
* There are cases where stacktrace.message is an Event object
* https://github.com/getsentry/sentry-javascript/issues/1949
* In this specific case we try to extract stacktrace.message.error.message
*/
function extractMessage(ex: Error & { message: { error?: Error } }): string {
const message = ex && ex.message;
if (!message) {
return 'No error message';
}
if (message.error && typeof message.error.message === 'string') {
return message.error.message;
}
return message;
}

// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108
const reactMinifiedRegexp = /Minified React error #\d+;/i;

function getPopSize(ex: Error & { framesToPop?: number }): number {
if (ex) {
if (typeof ex.framesToPop === 'number') {
return ex.framesToPop;
}

if (reactMinifiedRegexp.test(ex.message)) {
return 1;
}
}

return 0;
}
Loading