From 369041ca6a0ccfdab1e9c89615fa8e9106f24538 Mon Sep 17 00:00:00 2001 From: Mason McElvain <52104630+masonmcelvain@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:03:50 -0700 Subject: [PATCH 1/4] fix(sentry): turn on auto instrument server funcs https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-server-side-auto-instrumentation --- frontend/next.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/next.config.js b/frontend/next.config.js index 81f6fb32..880c90d1 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -149,7 +149,6 @@ const moduleExports = { return config; }, sentry: { - autoInstrumentServerFunctions: false, // Upload artifacts in dist/framework as well; this includes sourcemaps // for react and other next.js code widenClientFileUpload: true, From c55d58bf0b0f150baff1486b85738a773c6cc6c0 Mon Sep 17 00:00:00 2001 From: Mason McElvain <52104630+masonmcelvain@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:13:03 -0700 Subject: [PATCH 2/4] fix(sentry): update _error page Copy/pasted from https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#create-a-custom-_error-page --- frontend/pages/_error.js | 65 --------------------------------------- frontend/pages/_error.tsx | 38 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 65 deletions(-) delete mode 100644 frontend/pages/_error.js create mode 100644 frontend/pages/_error.tsx diff --git a/frontend/pages/_error.js b/frontend/pages/_error.js deleted file mode 100644 index 9ab1a293..00000000 --- a/frontend/pages/_error.js +++ /dev/null @@ -1,65 +0,0 @@ -import NextErrorComponent from 'next/error'; - -import * as Sentry from '@sentry/nextjs'; - -const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => { - if (!hasGetInitialPropsRun && err) { - // getInitialProps is not called in case of - // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass - // err via _app.js so it can be captured - Sentry.captureException(err); - // Flushing is not required in this case as it only happens on the client - } - - return ; -}; - -MyError.getInitialProps = async (context) => { - const errorInitialProps = await NextErrorComponent.getInitialProps(context); - - const { res, err, asPath } = context; - - // Workaround for https://github.com/vercel/next.js/issues/8592, mark when - // getInitialProps has run - errorInitialProps.hasGetInitialPropsRun = true; - - // Returning early because we don't want to log 404 errors to Sentry. - if (res?.statusCode === 404) { - return errorInitialProps; - } - - // Running on the server, the response object (`res`) is available. - // - // Next.js will pass an err on the server if a page's data fetching methods - // threw or returned a Promise that rejected - // - // Running on the client (browser), Next.js will provide an err if: - // - // - a page's `getInitialProps` threw or returned a Promise that rejected - // - an exception was thrown somewhere in the React lifecycle (render, - // componentDidMount, etc) that was caught by Next.js's React Error - // Boundary. Read more about what types of exceptions are caught by Error - // Boundaries: https://reactjs.org/docs/error-boundaries.html - - if (err) { - Sentry.captureException(err); - - // Flushing before returning is necessary if deploying to Vercel, see - // https://vercel.com/docs/platform/limits#streaming-responses - await Sentry.flush(2000); - - return errorInitialProps; - } - - // If this point is reached, getInitialProps was called without any - // information about what the error might be. This is unexpected and may - // indicate a bug introduced in Next.js, so record it in Sentry - Sentry.captureException( - new Error(`_error.js getInitialProps missing data at path: ${asPath}`) - ); - await Sentry.flush(2000); - - return errorInitialProps; -}; - -export default MyError; diff --git a/frontend/pages/_error.tsx b/frontend/pages/_error.tsx new file mode 100644 index 00000000..55785f91 --- /dev/null +++ b/frontend/pages/_error.tsx @@ -0,0 +1,38 @@ +/** + * NOTE: This requires `@sentry/nextjs` version 7.3.0 or higher. + * + * This page is loaded by Nextjs: + * - on the server, when data-fetching methods throw or reject + * - on the client, when `getInitialProps` throws or rejects + * - on the client, when a React lifecycle method throws or rejects, and it's + * caught by the built-in Nextjs error boundary + * + * See: + * - https://nextjs.org/docs/basic-features/data-fetching/overview + * - https://nextjs.org/docs/api-reference/data-fetching/get-initial-props + * - https://reactjs.org/docs/error-boundaries.html + */ + +import * as Sentry from '@sentry/nextjs'; +import type { NextPage } from 'next'; +import type { ErrorProps } from 'next/error'; +import NextErrorComponent from 'next/error'; + +const CustomErrorComponent: NextPage = (props) => { + // If you're using a Nextjs version prior to 12.2.1, uncomment this to + // compensate for https://github.com/vercel/next.js/issues/8592 + // Sentry.captureUnderscoreErrorException(props); + + return ; +}; + +CustomErrorComponent.getInitialProps = async (contextData) => { + // In case this is running in a serverless function, await this in order to give Sentry + // time to send the error before the lambda exits + await Sentry.captureUnderscoreErrorException(contextData); + + // This will contain the status code of the response + return NextErrorComponent.getInitialProps(contextData); +}; + +export default CustomErrorComponent; From 918f3e92764bcf7b1c43319a60e672f25711bf86 Mon Sep 17 00:00:00 2001 From: Mason McElvain <52104630+masonmcelvain@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:17:46 -0700 Subject: [PATCH 3/4] fix(sentry): delete unused export --- packages/sentry/index.tsx | 7 ------- packages/shopify-storefront-client/index.tsx | 1 - packages/shopify-storefront-client/package.json | 3 --- pnpm-lock.yaml | 3 --- 4 files changed, 14 deletions(-) diff --git a/packages/sentry/index.tsx b/packages/sentry/index.tsx index ed063040..b05fa799 100644 --- a/packages/sentry/index.tsx +++ b/packages/sentry/index.tsx @@ -36,13 +36,6 @@ export const applySentryFetchMiddleware = () => { } }; -export const reportException: CaptureWithContextFn = (e, context) => { - Sentry.captureException(e, (scope) => { - scope.setContext('request', context); - return scope; - }); -}; - const withSentry: FetchMiddleware = (fetcher, shouldSkipRequest) => async (input, init) => { if (shouldSkipRequest?.(input, init)) { diff --git a/packages/shopify-storefront-client/index.tsx b/packages/shopify-storefront-client/index.tsx index cd4246a3..8cafc108 100644 --- a/packages/shopify-storefront-client/index.tsx +++ b/packages/shopify-storefront-client/index.tsx @@ -1,4 +1,3 @@ -import { reportException } from '@ifixit/sentry'; import * as React from 'react'; interface ShopifyStorefrontClientOptions { diff --git a/packages/shopify-storefront-client/package.json b/packages/shopify-storefront-client/package.json index 2677374b..be679af6 100644 --- a/packages/shopify-storefront-client/package.json +++ b/packages/shopify-storefront-client/package.json @@ -4,9 +4,6 @@ "main": "./index.tsx", "types": "./index.tsx", "license": "MIT", - "dependencies": { - "@ifixit/sentry": "workspace:*" - }, "devDependencies": { "@types/react": "18.0.24", "@types/react-dom": "18.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 695c3c7e..b418c287 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -497,13 +497,10 @@ importers: packages/shopify-storefront-client: specifiers: - '@ifixit/sentry': workspace:* '@ifixit/tsconfig': workspace:* '@types/react': 18.0.24 '@types/react-dom': 18.0.8 typescript: 4.8.4 - dependencies: - '@ifixit/sentry': link:../sentry devDependencies: '@ifixit/tsconfig': link:../tsconfig '@types/react': 18.0.24 From 75152efa6d91ce4ca47c0950360a261b4fceb8b0 Mon Sep 17 00:00:00 2001 From: Mason McElvain <52104630+masonmcelvain@users.noreply.github.com> Date: Tue, 11 Apr 2023 13:30:28 -0700 Subject: [PATCH 4/4] fix(sentry): prevent duplicate events on server Sentry's server function auto-instrumentation should capture these errors for us. --- frontend/lib/shopify-storefront-sdk/index.ts | 3 +-- frontend/lib/strapi-sdk/index.ts | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/lib/shopify-storefront-sdk/index.ts b/frontend/lib/shopify-storefront-sdk/index.ts index 73e84870..b9a797be 100644 --- a/frontend/lib/shopify-storefront-sdk/index.ts +++ b/frontend/lib/shopify-storefront-sdk/index.ts @@ -45,9 +45,8 @@ export function getServerShopifyStorefrontSdk(shop: ShopCredentials) { scope.setExtra('query', doc); scope.setExtra('variables', variables); scope.setExtra('errors', result.errors); - Sentry.captureException(new Error(errorMessage)); + throw new Error(errorMessage); }); - throw new Error(errorMessage); } return result.data; }; diff --git a/frontend/lib/strapi-sdk/index.ts b/frontend/lib/strapi-sdk/index.ts index 6afa6acc..87ea65c0 100644 --- a/frontend/lib/strapi-sdk/index.ts +++ b/frontend/lib/strapi-sdk/index.ts @@ -39,9 +39,7 @@ const requester: Requester = async ( scope.setExtra('query', doc); scope.setExtra('variables', variables); scope.setExtra('errors', result.errors); - Sentry.captureException( - new Error('Strapi SDK GraphQL query failed with errors') - ); + throw new Error('Strapi SDK GraphQL query failed with errors'); }); } throw new Error(`GraphQL query failed to execute: ${response.statusText}`);