linkedErrors integrations

Created Diff never expires
16 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
78 lines
38 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
98 lines
import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types';
import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types';
import { isInstanceOf } from '@sentry/utils';
import { isInstanceOf, SyncPromise } from '@sentry/utils';


import { exceptionFromStacktrace } from '../parsers';
import { getExceptionFromError } from '../parsers';
import { computeStackTrace } from '../tracekit';


const DEFAULT_KEY = 'cause';
const DEFAULT_KEY = 'cause';
const DEFAULT_LIMIT = 5;
const DEFAULT_LIMIT = 5;


/** Adds SDK info to an event. */
/** Adds SDK info to an event. */
export class LinkedErrors implements Integration {
export class LinkedErrors implements Integration {
/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
public static id: string = 'LinkedErrors';
public static id: string = 'LinkedErrors';


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
public readonly name: string = LinkedErrors.id;
public readonly name: string = LinkedErrors.id;


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
private readonly _key: string;
private readonly _key: string;


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
private readonly _limit: number;
private readonly _limit: number;


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
public constructor(options: { key?: string; limit?: number } = {}) {
public constructor(options: { key?: string; limit?: number } = {}) {
this._key = options.key || DEFAULT_KEY;
this._key = options.key || DEFAULT_KEY;
this._limit = options.limit || DEFAULT_LIMIT;
this._limit = options.limit || DEFAULT_LIMIT;
}
}


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
public setupOnce(): void {
public setupOnce(): void {
addGlobalEventProcessor((event: Event, hint?: EventHint) => {
addGlobalEventProcessor((event: Event, hint?: EventHint) => {
const self = getCurrentHub().getIntegration(LinkedErrors);
const self = getCurrentHub().getIntegration(LinkedErrors);
if (self) {
if (self) {
return self._handler(event, hint);
const handler = self._handler && self._handler.bind(self);
return typeof handler === 'function' ? handler(event, hint) : event;
}
}
return event;
return event;
});
});
}
}


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
private _handler(event: Event, hint?: EventHint): Event | null {
private _handler(event: Event, hint?: EventHint): PromiseLike<Event> {
if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
return event;
return SyncPromise.resolve(event);
}
}
const linkedErrors = this._walkErrorTree(hint.originalException as ExtendedError, this._key);

event.exception.values = [...linkedErrors, ...event.exception.values];
return new SyncPromise<Event>(resolve => {
return event;
void this._walkErrorTree(hint.originalException as Error, this._key)
.then((linkedErrors: Exception[]) => {
if (event && event.exception && event.exception.values) {
event.exception.values = [...linkedErrors, ...event.exception.values];
}
resolve(event);
})
.then(null, () => {
resolve(event);
});
});
}
}


/**
/**
* @inheritDoc
* @inheritDoc
*/
*/
private _walkErrorTree(error: ExtendedError, key: string, stack: Exception[] = []): Exception[] {
private _walkErrorTree(error: ExtendedError, key: string, stack: Exception[] = []): PromiseLike<Exception[]> {
if (!isInstanceOf(error[key], Error) || stack.length + 1 >= this._limit) {
if (!isInstanceOf(error[key], Error) || stack.length + 1 >= this._limit) {
return stack;
return SyncPromise.resolve(stack);
}
}
const stacktrace = computeStackTrace(error[key]);
return new SyncPromise<Exception[]>((resolve, reject) => {
const exception = exceptionFromStacktrace(stacktrace);
void getExceptionFromError(error[key])
return this._walkErrorTree(error[key], key, [exception, ...stack]);
.then((exception: Exception) => {
void this._walkErrorTree(error[key], key, [exception, ...stack])
.then(resolve)
.then(null, () => {
reject();
});
})
.then(null, () => {
reject();
});
});
}
}
}
}