this repo has no description
1import { logger } from '@sentry/utils';
2
3/** Deduplication filter */
4class Dedupe {constructor() { Dedupe.prototype.__init.call(this); }
5 /**
6 * @inheritDoc
7 */
8 static __initStatic() {this.id = 'Dedupe';}
9
10 /**
11 * @inheritDoc
12 */
13 __init() {this.name = Dedupe.id;}
14
15 /**
16 * @inheritDoc
17 */
18
19 /**
20 * @inheritDoc
21 */
22 setupOnce(addGlobalEventProcessor, getCurrentHub) {
23 const eventProcessor = currentEvent => {
24 // We want to ignore any non-error type events, e.g. transactions or replays
25 // These should never be deduped, and also not be compared against as _previousEvent.
26 if (currentEvent.type) {
27 return currentEvent;
28 }
29
30 const self = getCurrentHub().getIntegration(Dedupe);
31 if (self) {
32 // Juuust in case something goes wrong
33 try {
34 if (_shouldDropEvent(currentEvent, self._previousEvent)) {
35 (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Event dropped due to being a duplicate of previously captured event.');
36 return null;
37 }
38 } catch (_oO) {
39 return (self._previousEvent = currentEvent);
40 }
41
42 return (self._previousEvent = currentEvent);
43 }
44 return currentEvent;
45 };
46
47 eventProcessor.id = this.name;
48 addGlobalEventProcessor(eventProcessor);
49 }
50} Dedupe.__initStatic();
51
52/** JSDoc */
53function _shouldDropEvent(currentEvent, previousEvent) {
54 if (!previousEvent) {
55 return false;
56 }
57
58 if (_isSameMessageEvent(currentEvent, previousEvent)) {
59 return true;
60 }
61
62 if (_isSameExceptionEvent(currentEvent, previousEvent)) {
63 return true;
64 }
65
66 return false;
67}
68
69/** JSDoc */
70function _isSameMessageEvent(currentEvent, previousEvent) {
71 const currentMessage = currentEvent.message;
72 const previousMessage = previousEvent.message;
73
74 // If neither event has a message property, they were both exceptions, so bail out
75 if (!currentMessage && !previousMessage) {
76 return false;
77 }
78
79 // If only one event has a stacktrace, but not the other one, they are not the same
80 if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) {
81 return false;
82 }
83
84 if (currentMessage !== previousMessage) {
85 return false;
86 }
87
88 if (!_isSameFingerprint(currentEvent, previousEvent)) {
89 return false;
90 }
91
92 if (!_isSameStacktrace(currentEvent, previousEvent)) {
93 return false;
94 }
95
96 return true;
97}
98
99/** JSDoc */
100function _isSameExceptionEvent(currentEvent, previousEvent) {
101 const previousException = _getExceptionFromEvent(previousEvent);
102 const currentException = _getExceptionFromEvent(currentEvent);
103
104 if (!previousException || !currentException) {
105 return false;
106 }
107
108 if (previousException.type !== currentException.type || previousException.value !== currentException.value) {
109 return false;
110 }
111
112 if (!_isSameFingerprint(currentEvent, previousEvent)) {
113 return false;
114 }
115
116 if (!_isSameStacktrace(currentEvent, previousEvent)) {
117 return false;
118 }
119
120 return true;
121}
122
123/** JSDoc */
124function _isSameStacktrace(currentEvent, previousEvent) {
125 let currentFrames = _getFramesFromEvent(currentEvent);
126 let previousFrames = _getFramesFromEvent(previousEvent);
127
128 // If neither event has a stacktrace, they are assumed to be the same
129 if (!currentFrames && !previousFrames) {
130 return true;
131 }
132
133 // If only one event has a stacktrace, but not the other one, they are not the same
134 if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) {
135 return false;
136 }
137
138 currentFrames = currentFrames ;
139 previousFrames = previousFrames ;
140
141 // If number of frames differ, they are not the same
142 if (previousFrames.length !== currentFrames.length) {
143 return false;
144 }
145
146 // Otherwise, compare the two
147 for (let i = 0; i < previousFrames.length; i++) {
148 const frameA = previousFrames[i];
149 const frameB = currentFrames[i];
150
151 if (
152 frameA.filename !== frameB.filename ||
153 frameA.lineno !== frameB.lineno ||
154 frameA.colno !== frameB.colno ||
155 frameA.function !== frameB.function
156 ) {
157 return false;
158 }
159 }
160
161 return true;
162}
163
164/** JSDoc */
165function _isSameFingerprint(currentEvent, previousEvent) {
166 let currentFingerprint = currentEvent.fingerprint;
167 let previousFingerprint = previousEvent.fingerprint;
168
169 // If neither event has a fingerprint, they are assumed to be the same
170 if (!currentFingerprint && !previousFingerprint) {
171 return true;
172 }
173
174 // If only one event has a fingerprint, but not the other one, they are not the same
175 if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) {
176 return false;
177 }
178
179 currentFingerprint = currentFingerprint ;
180 previousFingerprint = previousFingerprint ;
181
182 // Otherwise, compare the two
183 try {
184 return !!(currentFingerprint.join('') === previousFingerprint.join(''));
185 } catch (_oO) {
186 return false;
187 }
188}
189
190/** JSDoc */
191function _getExceptionFromEvent(event) {
192 return event.exception && event.exception.values && event.exception.values[0];
193}
194
195/** JSDoc */
196function _getFramesFromEvent(event) {
197 const exception = event.exception;
198
199 if (exception) {
200 try {
201 // @ts-ignore Object could be undefined
202 return exception.values[0].stacktrace.frames;
203 } catch (_oO) {
204 return undefined;
205 }
206 }
207 return undefined;
208}
209
210export { Dedupe };
211//# sourceMappingURL=dedupe.js.map