Skip to content

Commit 2c3430b

Browse files
Merge pull request #4 from harshshukla2807/05-error-tracking
05: error tracking
2 parents 1bd870a + cddc1ea commit 2c3430b

16 files changed

Lines changed: 2244 additions & 98 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ node_modules
1212
.env.test.local
1313
.env.production.local
1414

15+
#sentry env files
16+
.env.sentry-build-plugin
17+
1518
# Testing
1619
coverage
1720

.npmrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
public-hoist-pattern[]=*import-in-the-middle*
2+
public-hoist-pattern[]=*require-in-the-middle*

apps/web/app/(dashboard)/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ export default function Page() {
2020
<UserButton />
2121
<Button onClick={() => addUser()}>Add User</Button>
2222
<OrganizationSwitcher/>
23-
<div className="mx-auto w-full max-w-sm">
23+
{/* <div className="mx-auto w-full max-w-sm">
2424
{JSON.stringify(users, null, 2)}
25-
</div>
25+
</div> */}
2626
</div>
2727
</>
2828
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as Sentry from "@sentry/nextjs";
2+
export const dynamic = "force-dynamic";
3+
4+
class SentryExampleAPIError extends Error {
5+
constructor(message: string | undefined) {
6+
super(message);
7+
this.name = "SentryExampleAPIError";
8+
}
9+
}
10+
11+
// A faulty API route to test Sentry's error monitoring
12+
export function GET() {
13+
Sentry.logger.info("Sentry example API called");
14+
throw new SentryExampleAPIError(
15+
"This error is raised on the backend called by the example page.",
16+
);
17+
}

apps/web/app/global-error.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use client";
2+
3+
import * as Sentry from "@sentry/nextjs";
4+
import NextError from "next/error";
5+
import { useEffect } from "react";
6+
7+
export default function GlobalError({
8+
error,
9+
}: {
10+
error: Error & { digest?: string };
11+
}) {
12+
useEffect(() => {
13+
Sentry.captureException(error);
14+
}, [error]);
15+
16+
return (
17+
<html lang="en">
18+
<body>
19+
{/* `NextError` is the default Next.js error page component. Its type
20+
definition requires a `statusCode` prop. However, since the App Router
21+
does not expose status codes for errors, we simply pass 0 to render a
22+
generic error message. */}
23+
<NextError statusCode={0} />
24+
</body>
25+
</html>
26+
);
27+
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
"use client";
2+
3+
import * as Sentry from "@sentry/nextjs";
4+
import Head from "next/head";
5+
import { useEffect, useState } from "react";
6+
7+
class SentryExampleFrontendError extends Error {
8+
constructor(message: string | undefined) {
9+
super(message);
10+
this.name = "SentryExampleFrontendError";
11+
}
12+
}
13+
14+
export default function Page() {
15+
const [hasSentError, setHasSentError] = useState(false);
16+
const [isConnected, setIsConnected] = useState(true);
17+
18+
useEffect(() => {
19+
Sentry.logger.info("Sentry example page loaded");
20+
async function checkConnectivity() {
21+
const result = await Sentry.diagnoseSdkConnectivity();
22+
setIsConnected(result !== "sentry-unreachable");
23+
}
24+
checkConnectivity();
25+
}, []);
26+
27+
return (
28+
<div>
29+
<Head>
30+
<title>sentry-example-page</title>
31+
<meta name="description" content="Test Sentry for your Next.js app!" />
32+
</Head>
33+
34+
<main>
35+
<div className="flex-spacer" />
36+
<svg
37+
height="40"
38+
width="40"
39+
fill="none"
40+
xmlns="http://www.w3.org/2000/svg"
41+
role="img"
42+
aria-label="Sentry logo"
43+
>
44+
<path
45+
d="M21.85 2.995a3.698 3.698 0 0 1 1.353 1.354l16.303 28.278a3.703 3.703 0 0 1-1.354 5.053 3.694 3.694 0 0 1-1.848.496h-3.828a31.149 31.149 0 0 0 0-3.09h3.815a.61.61 0 0 0 .537-.917L20.523 5.893a.61.61 0 0 0-1.057 0l-3.739 6.494a28.948 28.948 0 0 1 9.63 10.453 28.988 28.988 0 0 1 3.499 13.78v1.542h-9.852v-1.544a19.106 19.106 0 0 0-2.182-8.85 19.08 19.08 0 0 0-6.032-6.829l-1.85 3.208a15.377 15.377 0 0 1 6.382 12.484v1.542H3.696A3.694 3.694 0 0 1 0 34.473c0-.648.17-1.286.494-1.849l2.33-4.074a8.562 8.562 0 0 1 2.689 1.536L3.158 34.17a.611.611 0 0 0 .538.917h8.448a12.481 12.481 0 0 0-6.037-9.09l-1.344-.772 4.908-8.545 1.344.77a22.16 22.16 0 0 1 7.705 7.444 22.193 22.193 0 0 1 3.316 10.193h3.699a25.892 25.892 0 0 0-3.811-12.033 25.856 25.856 0 0 0-9.046-8.796l-1.344-.772 5.269-9.136a3.698 3.698 0 0 1 3.2-1.849c.648 0 1.285.17 1.847.495Z"
46+
fill="currentcolor"
47+
/>
48+
</svg>
49+
<h1>sentry-example-page</h1>
50+
51+
<p className="description">
52+
Click the button below, and view the sample error on the Sentry{" "}
53+
<a
54+
target="_blank"
55+
rel="noopener"
56+
href="https://harshorg.sentry.io/issues/?project=4511263762284624"
57+
>
58+
Issues Page
59+
</a>
60+
. For more details about setting up Sentry,{" "}
61+
<a
62+
target="_blank"
63+
rel="noopener"
64+
href="https://docs.sentry.io/platforms/javascript/guides/nextjs/"
65+
>
66+
read our docs
67+
</a>
68+
.
69+
</p>
70+
71+
<button
72+
type="button"
73+
onClick={async () => {
74+
Sentry.logger.info("User clicked the button, throwing a sample error");
75+
await Sentry.startSpan(
76+
{
77+
name: "Example Frontend/Backend Span",
78+
op: "test",
79+
},
80+
async () => {
81+
const res = await fetch("/api/sentry-example-api");
82+
if (!res.ok) {
83+
setHasSentError(true);
84+
}
85+
},
86+
);
87+
throw new SentryExampleFrontendError(
88+
"This error is raised on the frontend of the example page.",
89+
);
90+
}}
91+
disabled={!isConnected}
92+
>
93+
<span>Throw Sample Error</span>
94+
</button>
95+
96+
{hasSentError ? (
97+
<p className="success">Error sent to Sentry.</p>
98+
) : !isConnected ? (
99+
<div className="connectivity-error">
100+
<p>
101+
It looks like network requests to Sentry are being blocked, which
102+
will prevent errors from being captured. Try disabling your
103+
ad-blocker to complete the test.
104+
</p>
105+
</div>
106+
) : (
107+
<div className="success_placeholder" />
108+
)}
109+
110+
<div className="flex-spacer" />
111+
</main>
112+
113+
<style>{`
114+
main {
115+
display: flex;
116+
min-height: 100vh;
117+
flex-direction: column;
118+
justify-content: center;
119+
align-items: center;
120+
gap: 16px;
121+
padding: 16px;
122+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
123+
}
124+
125+
h1 {
126+
padding: 0px 4px;
127+
border-radius: 4px;
128+
background-color: rgba(24, 20, 35, 0.03);
129+
font-family: monospace;
130+
font-size: 20px;
131+
line-height: 1.2;
132+
}
133+
134+
p {
135+
margin: 0;
136+
font-size: 20px;
137+
}
138+
139+
a {
140+
color: #6341F0;
141+
text-decoration: underline;
142+
cursor: pointer;
143+
144+
@media (prefers-color-scheme: dark) {
145+
color: #B3A1FF;
146+
}
147+
}
148+
149+
button {
150+
border-radius: 8px;
151+
color: white;
152+
cursor: pointer;
153+
background-color: #553DB8;
154+
border: none;
155+
padding: 0;
156+
margin-top: 4px;
157+
158+
& > span {
159+
display: inline-block;
160+
padding: 12px 16px;
161+
border-radius: inherit;
162+
font-size: 20px;
163+
font-weight: bold;
164+
line-height: 1;
165+
background-color: #7553FF;
166+
border: 1px solid #553DB8;
167+
transform: translateY(-4px);
168+
}
169+
170+
&:hover > span {
171+
transform: translateY(-8px);
172+
}
173+
174+
&:active > span {
175+
transform: translateY(0);
176+
}
177+
178+
&:disabled {
179+
cursor: not-allowed;
180+
opacity: 0.6;
181+
182+
& > span {
183+
transform: translateY(0);
184+
border: none
185+
}
186+
}
187+
}
188+
189+
.description {
190+
text-align: center;
191+
color: #6E6C75;
192+
max-width: 500px;
193+
line-height: 1.5;
194+
font-size: 20px;
195+
196+
@media (prefers-color-scheme: dark) {
197+
color: #A49FB5;
198+
}
199+
}
200+
201+
.flex-spacer {
202+
flex: 1;
203+
}
204+
205+
.success {
206+
padding: 12px 16px;
207+
border-radius: 8px;
208+
font-size: 20px;
209+
line-height: 1;
210+
background-color: #00F261;
211+
border: 1px solid #00BF4D;
212+
color: #181423;
213+
}
214+
215+
.success_placeholder {
216+
height: 46px;
217+
}
218+
219+
.connectivity-error {
220+
padding: 12px 16px;
221+
background-color: #E50045;
222+
border-radius: 8px;
223+
width: 500px;
224+
color: #FFFFFF;
225+
border: 1px solid #A80033;
226+
text-align: center;
227+
margin: 0;
228+
}
229+
230+
.connectivity-error a {
231+
color: #FFFFFF;
232+
text-decoration: underline;
233+
}
234+
`}</style>
235+
</div>
236+
);
237+
}

apps/web/instrumentation-client.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// This file configures the initialization of Sentry on the client.
2+
// The added config here will be used whenever a users loads a page in their browser.
3+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
4+
5+
import * as Sentry from "@sentry/nextjs";
6+
7+
Sentry.init({
8+
dsn: "https://beae85b497c0fef2306962605108c0bd@o4511263703302144.ingest.de.sentry.io/4511263762284624",
9+
10+
// Add optional integrations for additional features
11+
integrations: [Sentry.replayIntegration()],
12+
13+
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
14+
tracesSampleRate: 1,
15+
// Enable logs to be sent to Sentry
16+
enableLogs: true,
17+
18+
// Define how likely Replay events are sampled.
19+
// This sets the sample rate to be 10%. You may want this to be 100% while
20+
// in development and sample at a lower rate in production
21+
replaysSessionSampleRate: 0.1,
22+
23+
// Define how likely Replay events are sampled when an error occurs.
24+
replaysOnErrorSampleRate: 1.0,
25+
26+
// Enable sending user PII (Personally Identifiable Information)
27+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
28+
sendDefaultPii: true,
29+
});
30+
31+
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

apps/web/instrumentation.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Sentry from "@sentry/nextjs";
2+
3+
export async function register() {
4+
if (process.env.NEXT_RUNTIME === "nodejs") {
5+
await import("./sentry.server.config");
6+
}
7+
8+
if (process.env.NEXT_RUNTIME === "edge") {
9+
await import("./sentry.edge.config");
10+
}
11+
}
12+
13+
export const onRequestError = Sentry.captureRequestError;

0 commit comments

Comments
 (0)