@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
180 lines (141 loc) • 4.97 kB
JavaScript
import { defineIntegration } from '../integration.js';
import { DEBUG_BUILD } from '../debug-build.js';
import { logger } from '../utils-hoist/logger.js';
import { getFramesFromEvent } from '../utils-hoist/stacktrace.js';
const INTEGRATION_NAME = 'Dedupe';
const _dedupeIntegration = (() => {
let previousEvent;
return {
name: INTEGRATION_NAME,
processEvent(currentEvent) {
// We want to ignore any non-error type events, e.g. transactions or replays
// These should never be deduped, and also not be compared against as _previousEvent.
if (currentEvent.type) {
return currentEvent;
}
// Juuust in case something goes wrong
try {
if (_shouldDropEvent(currentEvent, previousEvent)) {
DEBUG_BUILD && logger.warn('Event dropped due to being a duplicate of previously captured event.');
return null;
}
} catch (_oO) {} // eslint-disable-line no-empty
return (previousEvent = currentEvent);
},
};
}) ;
/**
* Deduplication filter.
*/
const dedupeIntegration = defineIntegration(_dedupeIntegration);
/** only exported for tests. */
function _shouldDropEvent(currentEvent, previousEvent) {
if (!previousEvent) {
return false;
}
if (_isSameMessageEvent(currentEvent, previousEvent)) {
return true;
}
if (_isSameExceptionEvent(currentEvent, previousEvent)) {
return true;
}
return false;
}
function _isSameMessageEvent(currentEvent, previousEvent) {
const currentMessage = currentEvent.message;
const previousMessage = previousEvent.message;
// If neither event has a message property, they were both exceptions, so bail out
if (!currentMessage && !previousMessage) {
return false;
}
// If only one event has a stacktrace, but not the other one, they are not the same
if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) {
return false;
}
if (currentMessage !== previousMessage) {
return false;
}
if (!_isSameFingerprint(currentEvent, previousEvent)) {
return false;
}
if (!_isSameStacktrace(currentEvent, previousEvent)) {
return false;
}
return true;
}
function _isSameExceptionEvent(currentEvent, previousEvent) {
const previousException = _getExceptionFromEvent(previousEvent);
const currentException = _getExceptionFromEvent(currentEvent);
if (!previousException || !currentException) {
return false;
}
if (previousException.type !== currentException.type || previousException.value !== currentException.value) {
return false;
}
if (!_isSameFingerprint(currentEvent, previousEvent)) {
return false;
}
if (!_isSameStacktrace(currentEvent, previousEvent)) {
return false;
}
return true;
}
function _isSameStacktrace(currentEvent, previousEvent) {
let currentFrames = getFramesFromEvent(currentEvent);
let previousFrames = getFramesFromEvent(previousEvent);
// If neither event has a stacktrace, they are assumed to be the same
if (!currentFrames && !previousFrames) {
return true;
}
// If only one event has a stacktrace, but not the other one, they are not the same
if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) {
return false;
}
currentFrames = currentFrames ;
previousFrames = previousFrames ;
// If number of frames differ, they are not the same
if (previousFrames.length !== currentFrames.length) {
return false;
}
// Otherwise, compare the two
for (let i = 0; i < previousFrames.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const frameA = previousFrames[i];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const frameB = currentFrames[i];
if (
frameA.filename !== frameB.filename ||
frameA.lineno !== frameB.lineno ||
frameA.colno !== frameB.colno ||
frameA.function !== frameB.function
) {
return false;
}
}
return true;
}
function _isSameFingerprint(currentEvent, previousEvent) {
let currentFingerprint = currentEvent.fingerprint;
let previousFingerprint = previousEvent.fingerprint;
// If neither event has a fingerprint, they are assumed to be the same
if (!currentFingerprint && !previousFingerprint) {
return true;
}
// If only one event has a fingerprint, but not the other one, they are not the same
if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) {
return false;
}
currentFingerprint = currentFingerprint ;
previousFingerprint = previousFingerprint ;
// Otherwise, compare the two
try {
return !!(currentFingerprint.join('') === previousFingerprint.join(''));
} catch (_oO) {
return false;
}
}
function _getExceptionFromEvent(event) {
return event.exception?.values && event.exception.values[0];
}
export { _shouldDropEvent, dedupeIntegration };
//# sourceMappingURL=dedupe.js.map