Skip to content

Commit 101c31b

Browse files
feat(remix): Add wrapHandleErrorWithSentry (#10370)
- Exports a new wrapper `Sentry.wrapHandleErrorWithSentry` for custom `handleError` implementations. - This runs the original `handleError` implementation, then runs the Sentry's capture logic. - This PR also renames `wrapRemixHandleError` to `sentryHandleError`, to avoid confusion. We're still exporting `wrapRemixHandleError` as alias. --------- Co-authored-by: Abhijeet Prasad <[email protected]>
1 parent 2b20e06 commit 101c31b

File tree

7 files changed

+68
-8
lines changed

7 files changed

+68
-8
lines changed

MIGRATION.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,8 +1234,6 @@ export class HeaderComponent {
12341234
}
12351235
```
12361236

1237-
---
1238-
12391237
# Deprecations in 7.x
12401238

12411239
You can use the **Experimental** [@sentry/migr8](https://www.npmjs.com/package/@sentry/migr8) to automatically update
@@ -1371,6 +1369,19 @@ Instead of an `transactionContext` being passed to the `tracesSampler` callback,
13711369
will be removed in v8. Note that the `attributes` are only the attributes at span creation time, and some attributes may
13721370
only be set later during the span lifecycle (and thus not be available during sampling).
13731371

1372+
## Deprecate `wrapRemixHandleError` in Remix SDK (since v7.100.0)
1373+
1374+
This release deprecates `wrapRemixHandleError` in favor of using `sentryHandleError` from `@sentry/remix`. It can be
1375+
used as below:
1376+
1377+
```typescript
1378+
// entry.server.ts
1379+
1380+
export const handleError = Sentry.wrapHandleErrorWithSentry(() => {
1381+
// Custom handleError implementation
1382+
});
1383+
```
1384+
13741385
## Deprecate using `getClient()` to check if the SDK was initialized
13751386

13761387
In v8, `getClient()` will stop returning `undefined` if `Sentry.init()` was not called. For cases where this may be used

dev-packages/e2e-tests/test-applications/create-remix-app-v2/app/entry.server.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@ installGlobals();
2626

2727
const ABORT_DELAY = 5_000;
2828

29-
export const handleError = Sentry.wrapRemixHandleError;
29+
Sentry.init({
30+
environment: 'qa', // dynamic sampling bias to keep transactions
31+
dsn: process.env.E2E_TEST_DSN,
32+
// Performance Monitoring
33+
tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production!
34+
});
35+
36+
const handleErrorImpl = () => {
37+
Sentry.setTag('remix-test-tag', 'remix-test-value');
38+
};
39+
40+
export const handleError = Sentry.wrapHandleErrorWithSentry(handleErrorImpl);
3041

3142
export default function handleRequest(
3243
request: Request,

packages/remix/src/index.server.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ export {
103103
// Keeping the `*` exports for backwards compatibility and types
104104
export * from '@sentry/node';
105105

106-
export { captureRemixServerException, wrapRemixHandleError } from './utils/instrumentServer';
106+
export {
107+
captureRemixServerException,
108+
// eslint-disable-next-line deprecation/deprecation
109+
wrapRemixHandleError,
110+
sentryHandleError,
111+
wrapHandleErrorWithSentry,
112+
} from './utils/instrumentServer';
107113
export { ErrorBoundary, withErrorBoundary } from '@sentry/react';
108114
export { withSentry } from './client/performance';
109115
export { captureRemixErrorBoundaryError } from './client/errors';

packages/remix/src/utils/instrumentServer.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ async function extractResponseError(response: Response): Promise<unknown> {
8989
*
9090
* Should be used in `entry.server` like:
9191
*
92-
* export const handleError = Sentry.wrapRemixHandleError
92+
* export const handleError = Sentry.sentryHandleError
9393
*/
94-
export function wrapRemixHandleError(err: unknown, { request }: DataFunctionArgs): void {
94+
export function sentryHandleError(err: unknown, { request }: DataFunctionArgs): void {
9595
// We are skipping thrown responses here as they are handled by
9696
// `captureRemixServerException` at loader / action level
9797
// We don't want to capture them twice.
@@ -107,6 +107,28 @@ export function wrapRemixHandleError(err: unknown, { request }: DataFunctionArgs
107107
});
108108
}
109109

110+
/**
111+
* @deprecated Use `sentryHandleError` instead.
112+
*/
113+
export const wrapRemixHandleError = sentryHandleError;
114+
115+
/**
116+
* Sentry wrapper for Remix's `handleError` function.
117+
* Remix Docs: https://remix.run/docs/en/main/file-conventions/entry.server#handleerror
118+
*/
119+
export function wrapHandleErrorWithSentry(
120+
origHandleError: (err: unknown, args: { request: unknown }) => void,
121+
): (err: unknown, args: { request: unknown }) => void {
122+
return function (this: unknown, err: unknown, args: { request: unknown }): void {
123+
// This is expected to be void but just in case it changes in the future.
124+
const res = origHandleError.call(this, err, args);
125+
126+
sentryHandleError(err, args as DataFunctionArgs);
127+
128+
return res;
129+
};
130+
}
131+
110132
/**
111133
* Captures an exception happened in the Remix server.
112134
*

packages/remix/src/utils/vendor/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export type RemixRequestState = {
6161

6262
export type RemixRequest = Request &
6363
Record<symbol | string, RemixRequestState> & {
64-
agent: Agent | ((parsedURL: URL) => Agent) | undefined;
64+
agent?: Agent | ((parsedURL: URL) => Agent) | undefined;
6565
};
6666

6767
export type AppLoadContext = Record<string, unknown> & { __sentry_express_wrapped__?: boolean };

packages/remix/test/integration/app_v2/entry.server.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import type { EntryContext } from '@remix-run/node';
1313
import { RemixServer } from '@remix-run/react';
1414
import { renderToString } from 'react-dom/server';
1515

16-
export const handleError = Sentry.wrapRemixHandleError;
16+
const handleErrorImpl = () => {
17+
Sentry.setTag('remix-test-tag', 'remix-test-value');
18+
};
19+
20+
export const handleError = Sentry.wrapHandleErrorWithSentry(handleErrorImpl);
1721

1822
export default function handleRequest(
1923
request: Request,

packages/remix/test/integration/test/server/ssr.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ describe('Server Side Rendering', () => {
1919
},
2020
},
2121
},
22+
tags: useV2
23+
? {
24+
// Testing that the wrapped `handleError` correctly adds tags
25+
'remix-test-tag': 'remix-test-value',
26+
}
27+
: {},
2228
});
2329

2430
assertSentryEvent(event[2], {

0 commit comments

Comments
 (0)