sentry-javascript icon indicating copy to clipboard operation
sentry-javascript copied to clipboard

Put `Error.cause` in error data with `ExtraErrorData` integration

Open lbogdan opened this issue 3 years ago • 2 comments

Is there an existing issue for this?

  • [X] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
  • [X] I have reviewed the documentation https://docs.sentry.io/
  • [X] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases

How do you use Sentry?

Sentry Saas (sentry.io)

Which package are you using?

@sentry/node

SDK Version

7.36.0

SDK Setup

See below.

Steps to Reproduce

Given running the following script with node index.mjs:

// index.mjs
import Sentry from '@sentry/node';
import { ExtraErrorData } from '@sentry/integrations';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  integrations: [
    new ExtraErrorData(),
  ],
});

function lower() {
  const err = new Error('lower');
  err.lowerFoo = 'baz';
  throw err;
}

function upper() {
  try {
    lower();
  } catch (lowerErr) {
    const err = new Error('upper', { cause: lowerErr });
    err.upperFoo = 'bar';
    console.error(err);
    throw err;
  }
}

upper();

Expected Result

As the errors are linked, I'd expect to see the extra data for both.

Actual Result

I can only see extra data for the upper error:

image

, although lowerFoo: 'baz' shows in the console.log() breadcrumb:

image

lbogdan avatar Feb 03 '23 11:02 lbogdan

Hi, thanks for writing in! The reason the integration currently doesn't support cause is because that field is not enumerable and we're simply iterating over all of the fields when adding the extra data. We could probably add a case for cause with not too much effort. Currently, though, I am not sure when we will get to it but you could open a PR to speed up the process!

lforst avatar Feb 06 '23 08:02 lforst

In the meanwhile I replaced it with a beforeSend handler where I use something like

function getExtraData(err) {
  const result = {};
  let currentErr = err;
  let keyPrefix = '';
  let empty = true;
  do {
    for (const key of Object.keys(currentErr)) {
      result[`${keyPrefix}${key}`] = currentErr[key];
      empty = false;
    }
    currentErr = currentErr.cause;
    keyPrefix += 'cause.';
} while (currentErr);
  return empty ? undefined : result;
}

which returns

{
  upperFoo: 'bar',
  'cause.lowerFoo': 'baz'
}

Another related small nit is that when the error has no extra data, an empty object {} is still added to contexts, showing an empty section in the UI:

image

lbogdan avatar Feb 06 '23 09:02 lbogdan