|
2 | 2 | import { Event, StackFrame } from '@sentry/types';
|
3 | 3 |
|
4 | 4 | import { getGlobalObject } from './global';
|
| 5 | +import { logger } from './logger'; |
5 | 6 | import { snipLine } from './string';
|
6 | 7 |
|
7 | 8 | /**
|
@@ -241,3 +242,40 @@ export function stripUrlQueryAndFragment(urlPath: string): string {
|
241 | 242 | // eslint-disable-next-line no-useless-escape
|
242 | 243 | return urlPath.split(/[\?#]/, 1)[0];
|
243 | 244 | }
|
| 245 | + |
| 246 | +/** |
| 247 | + * Checks whether or not we've already captured the given exception (note: not an identical exception - the very object |
| 248 | + * in question), and marks it captured if not. |
| 249 | + * |
| 250 | + * Sometimes an error gets captured by more than one mechanism. (This happens, for example, in frameworks where we |
| 251 | + * intercept thrown errors, capture them, and then rethrow them so that the framework can handle them however it |
| 252 | + * normally would, which may or may not lead to them being caught again by something like the global error handler.) |
| 253 | + * This prevents us from actually recording it twice. |
| 254 | + * |
| 255 | + * Note: It will ignore primitives, as properties can't be set on them. {@link: Object.objectify} can be used on |
| 256 | + * exceptions to convert any that are primitives into their equivalent object wrapper forms so that this check will |
| 257 | + * always work. However, because we need to flag the exact object which will get rethrown, and because that rethrowing |
| 258 | + * happens outside of the event processing pipeline, the objectification must be done before the exception captured. |
| 259 | + * |
| 260 | + * @param A thrown exception to check or flag as having been seen |
| 261 | + * @returns `true` if the exception has already been captured, `false` if not (with the side effect of marking it seen) |
| 262 | + */ |
| 263 | +export function checkOrSetAlreadyCaught(exception: unknown): boolean { |
| 264 | + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access |
| 265 | + if ((exception as any)?.__sentry_captured__) { |
| 266 | + logger.log("Not capturing exception because it's already been captured."); |
| 267 | + return true; |
| 268 | + } |
| 269 | + |
| 270 | + try { |
| 271 | + // set it this way rather than by assignment so that it's not ennumerable and therefore isn't recorded by the |
| 272 | + // `ExtraErrorData` integration |
| 273 | + Object.defineProperty(exception, '__sentry_captured__', { |
| 274 | + value: true, |
| 275 | + }); |
| 276 | + } catch (err) { |
| 277 | + // `exception` is a primitive, so we can't mark it seen |
| 278 | + } |
| 279 | + |
| 280 | + return false; |
| 281 | +} |
0 commit comments