-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathsentry.utils.ts
More file actions
104 lines (91 loc) · 3.21 KB
/
sentry.utils.ts
File metadata and controls
104 lines (91 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Shared Sentry utilities for filtering noise across all configs
// Used by: sentry.client.config.ts, sentry.edge.config.ts, sentry.server.config.ts
import type { ErrorEvent } from '@sentry/nextjs'
/**
* Patterns to filter out from Sentry reporting.
* These are generally noise that doesn't require action.
*/
const IGNORED_ERRORS = {
// User-initiated cancellations (not bugs)
userRejected: [
'User rejected',
'user rejected',
'User denied',
'not allowed by the user',
'User cancelled',
'user cancelled',
'Request rejected',
'AbortError',
'The operation was aborted',
],
perks: ['This payment is not eligible for a perk'],
networkIssues: ['Network Error', 'Failed to fetch', 'Load failed'],
// Browser/extension noise (mostly client-side, but included for consistency)
browserNoise: [
'ResizeObserver loop',
'ResizeObserver loop limit exceeded',
'Script error.',
// Extension interference
'chrome-extension://',
'moz-extension://',
'safari-extension://',
],
// Third-party scripts we don't control
thirdParty: ['googletagmanager', 'gtag', 'analytics', 'hotjar', 'clarity', 'intercom', 'crisp'],
// Third-party SDK internal errors (not actionable)
thirdPartySdkErrors: [
'IndexedDB:Set:InternalError', // Vercel Analytics storage - fails in private browsing, not actionable
'Analytics SDK:', // Vercel Analytics errors
],
}
/**
* Check if error message matches any ignored pattern
*/
export function shouldIgnoreError(event: ErrorEvent): boolean {
const message = event.message || ''
const exceptionValue = event.exception?.values?.[0]?.value || ''
const exceptionType = event.exception?.values?.[0]?.type || ''
const culprit = (event as any).culprit || ''
const searchText = `${message} ${exceptionValue} ${exceptionType} ${culprit}`.toLowerCase()
// Check all ignore patterns
for (const patterns of Object.values(IGNORED_ERRORS)) {
for (const pattern of patterns) {
if (searchText.includes(pattern.toLowerCase())) {
return true
}
}
}
// Ignore errors from browser extensions (client-side only, but safe to check everywhere)
const frames = event.exception?.values?.[0]?.stacktrace?.frames || []
for (const frame of frames) {
const filename = frame.filename || ''
if (
filename.includes('chrome-extension://') ||
filename.includes('moz-extension://') ||
filename.includes('safari-extension://')
) {
return true
}
}
return false
}
/**
* Clean sensitive headers from events
*/
export function cleanSensitiveHeaders(event: ErrorEvent): void {
if (event.request?.headers) {
delete event.request.headers['Authorization']
delete event.request.headers['api-key']
delete event.request.headers['cookie']
}
}
/**
* Standard beforeSend handler for all Sentry configs
*/
export function beforeSendHandler(event: ErrorEvent): ErrorEvent | null {
if (shouldIgnoreError(event)) {
return null
}
cleanSensitiveHeaders(event)
return event
}