Do you want to request a feature or report a bug?
feature
What is the current behavior?
try {
somethingThatThrows();
} catch (innerError) {
let error = new Error('something failed!');
error.cause = innerError;
throw error;
}
With the current behavior only the outer/wrapping Error
is shown in the stack trace.
What is the desired behavior?
It would be great if the inner Error
was also displayed in the stacktrace view, roughly similar to how it is done for Java and Python.
I'm happy to help implement this with a bit of guidance :)
Can be done with event hints in new SDK now
@kamilogorek can you explain what you mean by "event hints" and how that will work with the cause
property?
Event and Breadcrumb hints are objects containing various information used to put together an event or a breadcrumb. For events, those are things like event_id
, originalException
, syntheticException
(used internally to generate cleaner stacktrace), and any other arbitrary data
that user attaches. For breadcrumbs it's all implementation dependent. For XHR requests, hint contains xhr object itself, for user interactions it contains DOM element and event name etc.
They are available in two places. beforeSend
/beforeBreadcrumb
and eventProcessors
. Those are two ways we'll allow users to modify what we put together.
Examples based on your cause
property (I use message
for ease of reading, but there's nothing stopping you from modifying event stacktrace frames).
beforeSend
/beforeBreadcrumb
:
import { init } from '@sentry/browser';
init({
dsn: 'https://[email protected]/123',
beforeSend(event, hint) {
const processedEvent = { ...event };
const cause = hint.originalException.cause;
if (cause) {
processedEvent.message = cause.message;
}
return processedEvent;
},
beforeBreadcrumb(breadcrumb, hint) {
if (breadcrumb.category === 'ui.click') {
const target = hint.event.target;
if (target.ariaLabel) breadcrumb.message = target.ariaLabel;
}
return breadcrumb;
},
});
eventProcessor
(this will be not used that often, but is great for writing custom plugins or share them across multiple projects - in form of an integration, more on this soon):
import { getCurrentHub } from '@sentry/browser';
getCurrentHub().configureScope(scope => {
scope.addEventProcessor(async (event, hint) => {
const processedEvent = { ...event };
const cause = hint.originalException.cause;
if (cause) {
processedEvent.message = cause.message;
}
return processedEvent;
});
});
hmm, if I understand correctly this would overwrite the original exception though, right? my hope was that it could display them in parallel like in Java/Python 馃
Can you show me an example of desired output?
This is an example of how it looks like in Java:
Exception in thread "main" java.lang.IllegalStateException: A book has a null property
at com.example.myproject.Author.getBookIds(Author.java:38)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
at com.example.myproject.Book.getId(Book.java:22)
at com.example.myproject.Author.getBookIds(Author.java:36)
... 1 more
try {
somethingThatThrows();
} catch (innerError) {
let error = new Error('something failed!');
error.cause = innerError;
throw error;
}
Without the cause
assignment in the snippet above you lose any information on the original cause of the exception, but if you throw the innerError
it might be cryptic for the end user and you can't include other information that might help resolve the issue. Ideally it would be possible to show both inner and outer exception (and possible even more nesting levels) like in the Java example above.
The platform itself doesn't support this use-case, so there's only this much we can do on the SDK side. In JS, there's only one "main" exception, and we don't have an easy way to display more.
I'd add this as an extra
data in the event itself, which'd give you enough information on the UI:
beforeSend(event, hint) {
const processedEvent = { ...event };
const cause = hint.originalException.cause;
if (cause) {
processedEvent.extra = {
...processedEvent.extra,
cause: {
type: cause.type
message: cause.message,
stack: cause.stack
}
}
}
return processedEvent;
}
I'd add this as an extra data in the event itself, which'd give you enough information on the UI
yeah, unfortunately the cause.stack
will be displayed without sourcemaps though :-/
The platform itself doesn't support this use-case
do you not support this for Java/Python either?
@Turbo87 like this? :)
exactly! 馃槏
I'm not sure, but I think the order needs to be flipped though. I'd expect to see the "Parent process error" on top of the other one 馃
It's PoC so far. I'll make it happen before the final release :)
Great, thanks a lot!!
@kamilogorek did this land yet?
nevermind, I just found https://github.com/getsentry/sentry-javascript/blob/4.2.3/packages/browser/src/integrations/linkederrors.ts 馃帀