-
Notifications
You must be signed in to change notification settings - Fork 156
fix: skip unwanted stackframe on custom errors for faulty browsers #3555
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
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3555 +/- ##
==========================================
- Coverage 92.11% 92.01% -0.11%
==========================================
Files 317 317
Lines 8082 8105 +23
Branches 1827 1835 +8
==========================================
+ Hits 7445 7458 +13
- Misses 637 647 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
/to-staging |
View all feedbacks in Devflow UI.
failed to update GIT_BASE_BRANCH: activity error (type: github.GithubService_GetFile, scheduledEventID: 31, startedEventID: 32, identity: 1@github-worker-8c57d5bd9-ql2c7@): GET https://api.github.com/repos/DataDog/browser-sdk/contents/.gitlab-ci.yml?ref=6f9271f5a31cd3bcc4ddfa8b2a5755fa2cf336fe: 504 We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists. [] (type: ErrorResponse, retryable: true) Details
If you need support, contact us on Slack #devflow with those details! |
/to-staging |
View all feedbacks in Devflow UI.
Commit b4b96ffdcc will soon be integrated into staging-22.
Commit b4b96ffdcc has been merged into staging-22 in merge commit c5b4e1612c. Check out the triggered pipeline on Gitlab 🦊 If you need to revert this integration, you can use the following command: |
…to staging-22 Integrated commit sha: b4b96ff Co-authored-by: leomelki <[email protected]>
/to-staging |
View all feedbacks in Devflow UI.
Commit b8edf0b10e will soon be integrated into staging-22.
Commit b8edf0b10e has been merged into staging-22 in merge commit cc692c8e83. Check out the triggered pipeline on Gitlab 🦊 If you need to revert this integration, you can use the following command: |
…to staging-22 Integrated commit sha: b8edf0b Co-authored-by: leomelki <[email protected]>
…s UNKNOWN_FUNCTION
let WRONGLY_REPORTING_CUSTOM_ERRORS: boolean | undefined | ||
|
||
function isWronglyReportingCustomErrors() { | ||
if (WRONGLY_REPORTING_CUSTOM_ERRORS !== undefined) { | ||
return WRONGLY_REPORTING_CUSTOM_ERRORS | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we initialize this when the file loads and avoid the if (WRONGLY_REPORTING_CUSTOM_ERRORS !== undefined)
?
And WRONGLY_REPORTING_CUSTOM_ERRORS
could be used directly, skipping isWronglyReportingCustomErrors
let WRONGLY_REPORTING_CUSTOM_ERRORS: boolean | undefined | |
function isWronglyReportingCustomErrors() { | |
if (WRONGLY_REPORTING_CUSTOM_ERRORS !== undefined) { | |
return WRONGLY_REPORTING_CUSTOM_ERRORS | |
} | |
const WRONGLY_REPORTING_CUSTOM_ERRORS = (function isWronglyReportingCustomErrors() { | |
... | |
})(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried but the linter doesn't like it :
CallExpression can have side effects when the module is evaluated. Maybe move it in a function declaration?eslint(local-rules/disallow-side-effects)
I can change the code to do this outside of a function but it think it would be way less clean
} | ||
} | ||
|
||
const [customError, normalError] = [DatadogTestCustomError, Error].map((errConstructor) => new errConstructor()) // so that both errors should exactly have the same stacktrace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: smart!
@@ -48,6 +48,33 @@ export function computeStackTrace(ex: unknown): StackTrace { | |||
}) | |||
} | |||
|
|||
if (stack.length > 0 && isWronglyReportingCustomErrors()) { | |||
// if we are wrongly reporting custom errors | |||
if (ex instanceof Error && isErrorCustomError(ex)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: the isErrorCustomError(ex)
check should not be needed here
suggestion: merge the two if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done ✅ (with the iserrorcustomerror to isnonnativeclassprototype function change)
const constructors: string[] = [] | ||
|
||
// go through each inherited constructor | ||
let cstr: object | undefined = ex | ||
while ((cstr = Object.getPrototypeOf(cstr)) !== Error.prototype && cstr) { | ||
const errorConstructorName = cstr.constructor?.name || UNKNOWN_FUNCTION | ||
constructors.push(errorConstructorName) | ||
} | ||
|
||
// traverse the stacktrace in reverse order because the stacktrace starts with the last inherited constructor | ||
// we check constructor names to ensure we remove the correct frame (and there isn't a weird unsupported environment behavior) | ||
for (let i = constructors.length - 1; i >= 0; i--) { | ||
if (stack[0]?.func === constructors[i]) { | ||
// if the first stack frame is the custom error constructor | ||
stack.shift() // remove it | ||
} else { | ||
break | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
Can we have something like this?
if (isWronglyReportingCustomErrors() && ex instanceof Error) {
let currentPrototype = Object.getPrototypeOf(ex)
while (
currentPrototype &&
isNonNativeClassPrototype(currentPrototype) &&
stack.length > 0 &&
stack[0].func === (currentPrototype.constructor.name || UNKNOWN_FUNCTION)
) {
stack.shift()
currentPrototype = Object.getPrototypeOf(currentPrototype)
}
}
with
function isNonNativeClassPrototype(prototype: object) {
return String(prototype.constructor).startsWith('class ')
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moving the currentPrototype assignment in the while loop would increase the build size slightly as we would have to initialize the variable. Is this necessary ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, WDYT of:
if (isWronglyReportingCustomErrors() && ex instanceof Error) {
let currentPrototype = ex
while (
(currentPrototype = Object.getPrototypeOf(currentPrototype)) &&
isNonNativeClassPrototype(currentPrototype) &&
stack.length > 0 &&
stack[0].func === (currentPrototype.constructor.name || UNKNOWN_FUNCTION)
) {
stack.shift()
}
}
It's a bit more cryptic but... I'd be fine with it.
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
Just found an INSANE behaviour from WebKit (not Firefox) : When a custom error class does not have a constructor defined, it is not shown in the parsed stacktrace. Why ? Because WebKit does not report its stackframe origin (line/file). Thus, the parsing fails. |
…tructor on webkit
dfd486b
to
734d990
Compare
734d990
to
79239b7
Compare
Done in f6346fd ✅ |
Motivation
Custom error stacktrace fix
Some browsers (safari/firefox) add the error constructor as a frame in the stacktrace.
In order to normalize the stacktrace, we need to remove it.
Changes
core/src/tools/stackTrace/computeStackTrace.ts
was changed :test/e2e/scenario/rum/errors.scenario.ts
was changed:Test instructions
Trigger a custom error in Chrome and in Firefox. They should now have the same stacktrace :
Tests done in staging
Checklist