Skip to content

Commit ead57f2

Browse files
Merge pull request #62 from MobilityData/feat/nextjs-sentry
feat: update sentry settings for nextjs
2 parents f8c1c3c + 293b2ab commit ead57f2

File tree

10 files changed

+1143
-88
lines changed

10 files changed

+1143
-88
lines changed
Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import * as Sentry from '@sentry/react';
2-
import packageJson from '../package.json';
3-
import * as React from 'react';
4-
import {
5-
createRoutesFromChildren,
6-
matchRoutes,
7-
useLocation,
8-
useNavigationType,
9-
} from 'react-router-dom';
1+
// This file configures the initialization of Sentry on the client.
2+
// The config you add here will be used whenever a user loads a page in their browser.
3+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
4+
5+
import * as Sentry from '@sentry/nextjs';
6+
import packageJson from './package.json';
107

118
// Helper to safely parse Sentry sample rates from environment variables
129
const parseSampleRate = (
@@ -40,35 +37,28 @@ const replaysOnErrorSampleRate = parseSampleRate(
4037
);
4138

4239
if (dsn.length > 0) {
43-
const routerTracingIntegration =
44-
Sentry.reactRouterV6BrowserTracingIntegration({
45-
useEffect: React.useEffect,
46-
useLocation,
47-
useNavigationType,
48-
createRoutesFromChildren,
49-
matchRoutes,
50-
});
51-
52-
const integrations = [];
53-
if (routerTracingIntegration != null) {
54-
integrations.push(routerTracingIntegration);
55-
}
56-
const replayIntegration = Sentry.replayIntegration?.();
57-
if (replayIntegration != null) {
58-
integrations.push(replayIntegration);
59-
}
60-
6140
Sentry.init({
6241
dsn,
6342
environment,
6443
release,
65-
integrations,
44+
45+
// Adjust this value in production, or use tracesSampler for greater control
6646
tracesSampleRate,
67-
replaysSessionSampleRate,
47+
48+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
49+
debug: false,
50+
6851
replaysOnErrorSampleRate,
52+
replaysSessionSampleRate,
53+
54+
// You can add integrations below. The Replay integration is enabled by
55+
// default when replaysSessionSampleRate or replaysOnErrorSampleRate > 0.
56+
integrations: [Sentry.replayIntegration()],
57+
6958
ignoreErrors: [/ResizeObserver loop limit exceeded/i],
59+
7060
beforeSend(event) {
71-
// remove user IP and geo context
61+
// Remove user IP and geo context for privacy
7262
if (event.user != null) {
7363
delete event.user.ip_address;
7464
}
@@ -80,5 +70,4 @@ if (dsn.length > 0) {
8070
});
8171
}
8272

83-
export const SentryErrorBoundary = Sentry.ErrorBoundary;
84-
export const captureException = Sentry.captureException;
73+
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

next.config.mjs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1+
import { withSentryConfig } from '@sentry/nextjs';
12
import createNextIntlPlugin from 'next-intl/plugin';
23

34
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
45

56
/** @type {import('next').NextConfig} */
67
const nextConfig = {};
78

8-
export default withNextIntl(nextConfig);
9+
export default withSentryConfig(withNextIntl(nextConfig), {
10+
// For all available options, see:
11+
12+
org: process.env.SENTRY_ORG,
13+
project: process.env.SENTRY_PROJECT,
14+
15+
// Upload source maps for readable stack traces (only when auth token is present)
16+
authToken: process.env.SENTRY_AUTH_TOKEN,
17+
18+
// Hides source maps from generated client bundles
19+
hideSourceMaps: true,
20+
21+
// Prevents Sentry from attempting to build when there is no auth token
22+
silent: !process.env.SENTRY_AUTH_TOKEN,
23+
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"@mui/x-date-pickers": "8.23.0",
1313
"@mui/x-tree-view": "8.23.0",
1414
"@reduxjs/toolkit": "^1.9.6",
15-
"@sentry/react": "^10.26.0",
15+
"@sentry/nextjs": "^10.42.0",
1616
"@turf/center": "^6.5.0",
1717
"@types/leaflet": "^1.9.12",
1818
"@types/lodash": "^4.17.20",

sentry.edge.config.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// This file configures the initialization of Sentry for edge features (middleware, edge routes).
2+
// The config you add here will be used whenever middleware or an edge route handles a request.
3+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
4+
5+
import * as Sentry from '@sentry/nextjs';
6+
import packageJson from './package.json';
7+
8+
// Helper to safely parse Sentry sample rates from environment variables
9+
const parseSampleRate = (
10+
value: string | undefined,
11+
defaultValue: number,
12+
): number => {
13+
const parsed = parseFloat(value ?? String(defaultValue));
14+
if (isNaN(parsed) || parsed < 0 || parsed > 1) {
15+
return defaultValue;
16+
}
17+
return parsed;
18+
};
19+
20+
const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN ?? '';
21+
const environment =
22+
process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ??
23+
process.env.NODE_ENV ??
24+
'mobility-feeds-dev';
25+
const release = packageJson.version;
26+
const tracesSampleRate = parseSampleRate(
27+
process.env.NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE,
28+
0.05,
29+
);
30+
31+
if (dsn.length > 0) {
32+
Sentry.init({
33+
dsn,
34+
environment,
35+
release,
36+
37+
// Adjust this value in production, or use tracesSampler for greater control
38+
tracesSampleRate,
39+
40+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
41+
debug: false,
42+
});
43+
}

sentry.server.config.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// This file configures the initialization of Sentry on the server.
2+
// The config you add here will be used whenever the server handles a request.
3+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
4+
5+
import * as Sentry from '@sentry/nextjs';
6+
import packageJson from './package.json';
7+
8+
// Helper to safely parse Sentry sample rates from environment variables
9+
const parseSampleRate = (
10+
value: string | undefined,
11+
defaultValue: number,
12+
): number => {
13+
const parsed = parseFloat(value ?? String(defaultValue));
14+
if (isNaN(parsed) || parsed < 0 || parsed > 1) {
15+
return defaultValue;
16+
}
17+
return parsed;
18+
};
19+
20+
const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN ?? '';
21+
const environment =
22+
process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ??
23+
process.env.NODE_ENV ??
24+
'mobility-feeds-dev';
25+
const release = packageJson.version;
26+
const tracesSampleRate = parseSampleRate(
27+
process.env.NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE,
28+
0.05,
29+
);
30+
31+
if (dsn.length > 0) {
32+
Sentry.init({
33+
dsn,
34+
environment,
35+
release,
36+
37+
// Adjust this value in production, or use tracesSampler for greater control
38+
tracesSampleRate,
39+
40+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
41+
debug: false,
42+
});
43+
}

src/app/[locale]/error.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use client';
2+
3+
import * as Sentry from '@sentry/nextjs';
4+
import { useEffect } from 'react';
5+
import SentryErrorFallback from '../components/SentryErrorFallback';
6+
7+
/**
8+
* Next.js App Router error boundary for the [locale] segment.
9+
* Captures rendering errors and forwards them to Sentry.
10+
* See: https://nextjs.org/docs/app/building-your-application/routing/error-handling
11+
*/
12+
export default function Error({
13+
error,
14+
reset,
15+
}: {
16+
error: Error & { digest?: string };
17+
reset: () => void;
18+
}): React.ReactElement {
19+
useEffect(() => {
20+
Sentry.captureException(error);
21+
}, [error]);
22+
23+
return <SentryErrorFallback error={error} resetError={reset} />;
24+
}

src/app/[locale]/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 { useEffect } from 'react';
5+
6+
/**
7+
* Next.js App Router global error boundary.
8+
* This captures errors that occur in the root layout and sends them to Sentry.
9+
* See: https://nextjs.org/docs/app/building-your-application/routing/error-handling
10+
*/
11+
export default function GlobalError({
12+
error,
13+
}: {
14+
error: Error & { digest?: string };
15+
}): React.ReactElement {
16+
useEffect(() => {
17+
Sentry.captureException(error);
18+
}, [error]);
19+
20+
return (
21+
<html>
22+
<body>
23+
<h2>Something went wrong!</h2>
24+
</body>
25+
</html>
26+
);
27+
}

src/app/store/store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import createSagaMiddleware from '@redux-saga/core';
1818
import rootSaga from './saga/root-saga';
1919

2020
import rootReducer from './reducers';
21-
import { createReduxEnhancer } from '@sentry/react';
21+
import { createReduxEnhancer } from '@sentry/nextjs';
2222

2323
const persistConfig = {
2424
key: 'root',

src/instrumentation.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
/**
2-
* Next.js Instrumentation for MSW (Mock Service Worker)
2+
* Next.js Instrumentation
33
*
4-
* This file enables API mocking during e2e tests by intercepting
5-
* server-side fetch requests.
4+
* This file handles:
5+
* 1. Sentry server-side initialization (via @sentry/nextjs)
6+
* 2. MSW (Mock Service Worker) for API mocking during e2e tests
67
*
78
* MSW is only enabled when NEXT_PUBLIC_API_MOCKING is set to 'enabled'
89
*/
910

1011
export async function register(): Promise<void> {
12+
if (process.env.NEXT_RUNTIME === 'nodejs') {
13+
// Initialize Sentry for the Node.js runtime
14+
await import('../sentry.server.config');
15+
}
16+
17+
if (process.env.NEXT_RUNTIME === 'edge') {
18+
// Initialize Sentry for the Edge runtime
19+
await import('../sentry.edge.config');
20+
}
21+
1122
if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
1223
if (process.env.NEXT_RUNTIME === 'nodejs') {
1324
const { server } = await import('./mocks/server');
@@ -18,3 +29,5 @@ export async function register(): Promise<void> {
1829
}
1930
}
2031
}
32+
33+
export { captureRequestError as onRequestError } from '@sentry/nextjs';

0 commit comments

Comments
 (0)