Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 21 additions & 32 deletions src/sentry.ts → instrumentation-client.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import * as Sentry from '@sentry/react';
import packageJson from '../package.json';
import * as React from 'react';
import {
createRoutesFromChildren,
matchRoutes,
useLocation,
useNavigationType,
} from 'react-router-dom';
// This file configures the initialization of Sentry on the client.
// The config you add here will be used whenever a user loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs';
import packageJson from './package.json';

// Helper to safely parse Sentry sample rates from environment variables
const parseSampleRate = (
Expand Down Expand Up @@ -40,35 +37,28 @@ const replaysOnErrorSampleRate = parseSampleRate(
);

if (dsn.length > 0) {
const routerTracingIntegration =
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
});

const integrations = [];
if (routerTracingIntegration != null) {
integrations.push(routerTracingIntegration);
}
const replayIntegration = Sentry.replayIntegration?.();
if (replayIntegration != null) {
integrations.push(replayIntegration);
}

Sentry.init({
dsn,
environment,
release,
integrations,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate,
replaysSessionSampleRate,

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,

replaysOnErrorSampleRate,
replaysSessionSampleRate,

// You can add integrations below. The Replay integration is enabled by
// default when replaysSessionSampleRate or replaysOnErrorSampleRate > 0.
integrations: [Sentry.replayIntegration()],

ignoreErrors: [/ResizeObserver loop limit exceeded/i],

beforeSend(event) {
// remove user IP and geo context
// Remove user IP and geo context for privacy
if (event.user != null) {
delete event.user.ip_address;
}
Expand All @@ -80,5 +70,4 @@ if (dsn.length > 0) {
});
}

export const SentryErrorBoundary = Sentry.ErrorBoundary;
export const captureException = Sentry.captureException;
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
17 changes: 16 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { withSentryConfig } from '@sentry/nextjs';
import createNextIntlPlugin from 'next-intl/plugin';

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

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

export default withNextIntl(nextConfig);
export default withSentryConfig(withNextIntl(nextConfig), {
// For all available options, see:

org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,

// Upload source maps for readable stack traces (only when auth token is present)
authToken: process.env.SENTRY_AUTH_TOKEN,

// Hides source maps from generated client bundles
hideSourceMaps: true,

// Prevents Sentry from attempting to build when there is no auth token
silent: !process.env.SENTRY_AUTH_TOKEN,
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@mui/x-date-pickers": "8.23.0",
"@mui/x-tree-view": "8.23.0",
"@reduxjs/toolkit": "^1.9.6",
"@sentry/react": "^10.26.0",
"@sentry/nextjs": "^10.42.0",
"@turf/center": "^6.5.0",
"@types/leaflet": "^1.9.12",
"@types/lodash": "^4.17.20",
Expand Down
43 changes: 43 additions & 0 deletions sentry.edge.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// This file configures the initialization of Sentry for edge features (middleware, edge routes).
// The config you add here will be used whenever middleware or an edge route handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs';
import packageJson from './package.json';

// Helper to safely parse Sentry sample rates from environment variables
const parseSampleRate = (
value: string | undefined,
defaultValue: number,
): number => {
const parsed = parseFloat(value ?? String(defaultValue));
if (isNaN(parsed) || parsed < 0 || parsed > 1) {
return defaultValue;
}
return parsed;
};

const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN ?? '';
const environment =
process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ??
process.env.NODE_ENV ??
'mobility-feeds-dev';
const release = packageJson.version;
const tracesSampleRate = parseSampleRate(
process.env.NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE,
0.05,
);

if (dsn.length > 0) {
Sentry.init({
dsn,
environment,
release,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate,

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
});
}
43 changes: 43 additions & 0 deletions sentry.server.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs';
import packageJson from './package.json';

// Helper to safely parse Sentry sample rates from environment variables
const parseSampleRate = (
value: string | undefined,
defaultValue: number,
): number => {
const parsed = parseFloat(value ?? String(defaultValue));
if (isNaN(parsed) || parsed < 0 || parsed > 1) {
return defaultValue;
}
return parsed;
};

const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN ?? '';
const environment =
process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ??
process.env.NODE_ENV ??
'mobility-feeds-dev';
const release = packageJson.version;
const tracesSampleRate = parseSampleRate(
process.env.NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE,
0.05,
);

if (dsn.length > 0) {
Sentry.init({
dsn,
environment,
release,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate,

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
});
}
24 changes: 24 additions & 0 deletions src/app/[locale]/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client';

import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';
import SentryErrorFallback from '../components/SentryErrorFallback';

/**
* Next.js App Router error boundary for the [locale] segment.
* Captures rendering errors and forwards them to Sentry.
* See: https://nextjs.org/docs/app/building-your-application/routing/error-handling
*/
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}): React.ReactElement {
useEffect(() => {
Sentry.captureException(error);
}, [error]);

return <SentryErrorFallback error={error} resetError={reset} />;
}
27 changes: 27 additions & 0 deletions src/app/[locale]/global-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';

/**
* Next.js App Router global error boundary.
* This captures errors that occur in the root layout and sends them to Sentry.
* See: https://nextjs.org/docs/app/building-your-application/routing/error-handling
*/
export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}): React.ReactElement {
useEffect(() => {
Sentry.captureException(error);
}, [error]);

return (
<html>
<body>
<h2>Something went wrong!</h2>
</body>
</html>
);
}
2 changes: 1 addition & 1 deletion src/app/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import createSagaMiddleware from '@redux-saga/core';
import rootSaga from './saga/root-saga';

import rootReducer from './reducers';
import { createReduxEnhancer } from '@sentry/react';
import { createReduxEnhancer } from '@sentry/nextjs';

const persistConfig = {
key: 'root',
Expand Down
19 changes: 16 additions & 3 deletions src/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
/**
* Next.js Instrumentation for MSW (Mock Service Worker)
* Next.js Instrumentation
*
* This file enables API mocking during e2e tests by intercepting
* server-side fetch requests.
* This file handles:
* 1. Sentry server-side initialization (via @sentry/nextjs)
* 2. MSW (Mock Service Worker) for API mocking during e2e tests
*
* MSW is only enabled when NEXT_PUBLIC_API_MOCKING is set to 'enabled'
*/

export async function register(): Promise<void> {
if (process.env.NEXT_RUNTIME === 'nodejs') {
// Initialize Sentry for the Node.js runtime
await import('../sentry.server.config');
}

if (process.env.NEXT_RUNTIME === 'edge') {
// Initialize Sentry for the Edge runtime
await import('../sentry.edge.config');
}

if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { server } = await import('./mocks/server');
Expand All @@ -18,3 +29,5 @@ export async function register(): Promise<void> {
}
}
}

export { captureRequestError as onRequestError } from '@sentry/nextjs';
Loading