-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstrumentation-client.ts
More file actions
167 lines (144 loc) · 4.52 KB
/
instrumentation-client.ts
File metadata and controls
167 lines (144 loc) · 4.52 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// This file configures the initialization of Sentry on the client.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
const initClientSentry = () => {
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Environment configuration
environment: process.env.NODE_ENV || "development",
// Release tracking
release:
process.env.SENTRY_RELEASE ||
process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA ||
undefined,
// Performance Monitoring - 100% in dev, 10% in prod
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,
// Session Replay - 10% of sessions, 100% of sessions with errors
replaysSessionSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 0,
replaysOnErrorSampleRate: 1.0,
// Integrations
integrations: [
Sentry.browserTracingIntegration({
enableInp: true,
}),
Sentry.replayIntegration({
maskAllText: false,
blockAllMedia: false,
networkDetailAllowUrls: ["/api/"],
networkRequestHeaders: ["Content-Type", "Content-Length"],
networkResponseHeaders: ["Content-Type"],
}),
],
// Filter and enrich errors before sending
beforeSend(event) {
// Don't send errors in development unless explicitly enabled
if (process.env.NODE_ENV === "development" && !process.env.SENTRY_DEBUG) {
console.log(
"[Sentry] Event captured (dev mode):",
event.message || event.exception?.values?.[0]?.value
);
return null;
}
// Filter out common non-actionable errors
const errorMessage = event.exception?.values?.[0]?.value || "";
// Ignore ResizeObserver errors (browser quirk)
if (errorMessage.includes("ResizeObserver loop")) {
return null;
}
// Ignore cancelled requests (user navigated away)
if (
errorMessage.includes("AbortError") ||
errorMessage.includes("The user aborted a request")
) {
return null;
}
// Add custom tags for easier filtering
event.tags = {
...event.tags,
app_version: process.env.NEXT_PUBLIC_APP_VERSION || "unknown",
is_mobile:
typeof window !== "undefined" && window.innerWidth < 768
? "true"
: "false",
};
return event;
},
// Add breadcrumbs for better debugging context
beforeBreadcrumb(breadcrumb) {
if (breadcrumb.category === "console" && breadcrumb.level === "log") {
return null;
}
return breadcrumb;
},
// Debug mode
debug: process.env.SENTRY_DEBUG === "true",
// Session tracking (Note: autoSessionTracking removed as it's no longer supported)
attachStacktrace: true,
maxBreadcrumbs: 50,
// Ignore specific errors
ignoreErrors: [
"top.GLOBALS",
"chrome-extension://",
"moz-extension://",
"safari-extension://",
"Network request failed",
"Failed to fetch",
"Load failed",
"AbortError",
// Ad-blocker errors - don't let these affect navigation or be reported
"ERR_BLOCKED_BY_CLIENT",
"net::ERR_BLOCKED_BY_CLIENT",
],
// Deny URLs
denyUrls: [
/extensions\//i,
/^chrome:\/\//i,
/^chrome-extension:\/\//i,
/^moz-extension:\/\//i,
/^safari-extension:\/\//i,
],
// Enable PII for better debugging
sendDefaultPii: true,
});
};
// Wrap router transition tracking to prevent ad-blocker errors from breaking navigation
// When ad blockers block /monitoring, the network error could interrupt client-side navigation
export const onRouterTransitionStart = (
...args: Parameters<typeof Sentry.captureRouterTransitionStart>
) => {
try {
return Sentry.captureRouterTransitionStart(...args);
} catch {
// Silently ignore - don't let Sentry failures break navigation
}
};
// Helper: Set user context after authentication
export const setSentryUser = (user: { id: string; name?: string } | null) => {
if (user) {
Sentry.setUser({
id: user.id,
username: user.name,
});
} else {
Sentry.setUser(null);
}
};
// Helper: Capture errors with additional context
export const captureError = (error: Error, context: Record<string, unknown> = {}) => {
Sentry.captureException(error, {
extra: context,
});
};
// Helper: Add custom breadcrumb
export const addBreadcrumb = (
message: string,
category = "custom",
data: Record<string, unknown> = {}
) => {
Sentry.addBreadcrumb({
message,
category,
data,
level: "info",
});
};