-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(sentry): fix sentry unhandled rejection (#4270)
* fix: do not throw handled error * refactor: extract breadcrumbs checking to an external fn * refactor: move cow-react/sentry.ts to cow-react/sentry/index.ts * refactor: move beforeSend to its own file * feat: ignore metamask unhandled rejection error * refactor: rename fn * fix: ignore errors based on error code * fix: add one more error code * chore: remove debug statements
- widget-react-v0.11.0
- widget-react-v0.10.2
- widget-react-v0.10.1
- widget-react-v0.10.0
- widget-lib-v0.18.1
- widget-lib-v0.18.0
- widget-lib-v0.17.0
- widget-lib-v0.16.0
- widget-lib-v0.15.0
- widget-lib-v0.14.1
- widget-lib-v0.14.0
- widget-lib-v0.13.2
- widget-lib-v0.13.1
- widget-lib-v0.13.0
- widget-lib-v0.12.0
- widget-configurator-v1.13.0
- widget-configurator-v1.12.0
- widget-configurator-v1.11.0
- widget-configurator-v1.10.1
- widget-configurator-v1.10.0
- widget-configurator-v1.9.0
- widget-configurator-v1.8.0
- widget-configurator-v1.7.2
- widget-configurator-v1.7.1
- widget-configurator-v1.7.0
- widget-configurator-v1.6.0
- widget-configurator-v1.5.1
- widget-configurator-v1.5.0
- widget-configurator-v1.4.0
- widget-configurator-v1.3.2
- widget-configurator-v1.3.1
- widget-configurator-v1.3.0
- widget-configurator-v1.2.1
- wallet-v1.10.1
- wallet-v1.10.0
- wallet-v1.9.3
- wallet-v1.9.2
- wallet-v1.9.1
- wallet-v1.9.0
- wallet-v1.8.1
- wallet-v1.8.0
- wallet-v1.7.0
- wallet-v1.6.1
- wallet-v1.6.0
- wallet-v1.5.2
- wallet-v1.5.1
- wallet-v1.5.0
- wallet-v1.4.1
- wallet-v1.4.0
- wallet-v1.3.0
- wallet-provider-v1.0.0
- ui-v1.21.0
- ui-v1.20.0
- ui-v1.19.0
- ui-v1.18.0
- ui-v1.17.1
- ui-v1.17.0
- ui-v1.16.0
- ui-v1.15.0
- ui-v1.14.0
- ui-v1.13.0
- ui-v1.12.0
- ui-v1.11.0
- ui-v1.10.1
- ui-v1.10.0
- ui-v1.9.0
- ui-v1.8.1
- ui-v1.8.0
- ui-v1.7.1
- ui-v1.7.0
- ui-v1.6.0
- ui-v1.5.0
- ui-v1.4.1
- ui-v1.4.0
- ui-v1.3.0
- ui-v1.2.1
- ui-utils-v1.1.0
- ui-utils-v1.0.0
- types-v1.5.1
- types-v1.5.0
- types-v1.4.0
- types-v1.3.0
- types-v1.2.0
- types-v1.1.0
- tokens-v1.15.0
- tokens-v1.14.1
- tokens-v1.14.0
- tokens-v1.13.1
- tokens-v1.13.0
- tokens-v1.12.0
- tokens-v1.11.0
- tokens-v1.10.0
- tokens-v1.9.0
- tokens-v1.8.1
- tokens-v1.8.0
- tokens-v1.7.0
- tokens-v1.6.1
- tokens-v1.6.0
- tokens-v1.5.2
- tokens-v1.5.1
- tokens-v1.5.0
- tokens-v1.4.1
- tokens-v1.4.0
- tokens-v1.3.1
- tokens-v1.3.0
- snackbars-v1.1.1
- snackbars-v1.1.0
- permit-utils-v0.6.0
- permit-utils-v0.5.0
- permit-utils-v0.4.0
- permit-utils-v0.3.1
- permit-utils-v0.3.0
- multicall-v1.0.0
- iframe-transport-v1.0.1
- iframe-transport-v1.0.0
- hook-dapp-lib-v1.6.0
- hook-dapp-lib-v1.5.0
- hook-dapp-lib-v1.4.0
- hook-dapp-lib-v1.3.0
- hook-dapp-lib-v1.2.0
- hook-dapp-lib-v1.1.0
- hook-dapp-lib-v1.0.0
- explorer-v2.44.0
- explorer-v2.43.0
- explorer-v2.42.2
- explorer-v2.42.1
- explorer-v2.42.0
- explorer-v2.41.0
- explorer-v2.40.1
- explorer-v2.40.0
- explorer-v2.39.0
- explorer-v2.38.0
- explorer-v2.37.0
- explorer-v2.36.1
- explorer-v2.36.0
- explorer-v2.35.2
- explorer-v2.35.1
- explorer-v2.35.0
- explorer-v2.34.1
- explorer-v2.34.0
- explorer-v2.33.1
- explorer-v2.33.0
- explorer-v2.32.3
- explorer-v2.32.2
- explorer-v2.32.1
- explorer-v2.32.0
- explorer-v2.31.1
- explorer-v2.31.0
- explorer-v2.30.1
- explorer-v2.30.0
- explorer-v2.29.6
- events-v1.5.0
- events-v1.4.1
- events-v1.4.0
- ens-v1.3.0
- ens-v1.2.0
- ens-v1.1.0
- cowswap-v1.103.5
- cowswap-v1.103.4
- cowswap-v1.103.3
- cowswap-v1.103.2
- cowswap-v1.103.1
- cowswap-v1.103.0
- cowswap-v1.102.0
- cowswap-v1.101.0
- cowswap-v1.100.1
- cowswap-v1.100.0
- cowswap-v1.99.0
- cowswap-v1.98.2
- cowswap-v1.98.1
- cowswap-v1.98.0
- cowswap-v1.97.1
- cowswap-v1.97.0
- cowswap-v1.96.2
- cowswap-v1.96.1
- cowswap-v1.96.0
- cowswap-v1.95.3
- cowswap-v1.95.2
- cowswap-v1.95.1
- cowswap-v1.95.0
- cowswap-v1.94.0
- cowswap-v1.93.2
- cowswap-v1.93.1
- cowswap-v1.93.0
- cowswap-v1.92.2
- cowswap-v1.92.1
- cowswap-v1.92.0
- cowswap-v1.91.0
- cowswap-v1.90.0
- cowswap-v1.89.0
- cowswap-v1.88.0
- cowswap-v1.87.0
- cowswap-v1.86.1
- cowswap-v1.86.0
- cowswap-v1.85.0
- cowswap-v1.84.0
- cowswap-v1.83.0
- cowswap-v1.82.0
- cowswap-v1.81.2
- cowswap-v1.81.1
- cowswap-v1.81.0
- cowswap-v1.80.0
- cowswap-v1.79.0
- cowswap-v1.78.2
- cowswap-v1.78.1
- cowswap-v1.78.0
- cowswap-v1.77.1
- cowswap-v1.77.0
- cowswap-v1.76.2
- cowswap-v1.76.1
- cowswap-v1.76.0
- cowswap-v1.75.0
- cowswap-v1.74.1
- cowswap-v1.74.0
- cowswap-v1.73.0
- cowswap-v1.72.1
- cowswap-v1.72.0
- cowswap-v1.71.1
- cowswap-v1.71.0
- cowswap-v1.70.0
- cowswap-abis-v1.2.1
- cowswap-abis-v1.2.0
- cowswap-abis-v1.1.0
- cowswap-abis-v1.0.0
- cow-fi-v1.21.1
- cow-fi-v1.21.0
- cow-fi-v1.20.0
- cow-fi-v1.19.4
- cow-fi-v1.19.3
- cow-fi-v1.19.2
- cow-fi-v1.19.1
- cow-fi-v1.19.0
- cow-fi-v1.18.0
- cow-fi-v1.17.0
- cow-fi-v1.16.0
- cow-fi-v1.15.0
- cow-fi-v1.14.0
- cow-fi-v1.13.0
- cow-fi-v1.12.0
- cow-fi-v1.11.0
- cow-fi-v1.10.0
- cow-fi-v1.9.0
- cow-fi-v1.8.0
- cow-fi-v1.7.0
- cow-fi-v1.6.0
- cow-fi-v1.5.0
- cow-fi-v1.4.2
- cow-fi-v1.4.1
- cow-fi-v1.4.0
- cow-fi-v1.3.0
- cow-fi-v1.2.1
- cow-fi-v1.2.0
- cow-fi-v1.1.0
- cow-fi-v1.0.0
- core-v1.7.0
- core-v1.6.0
- core-v1.5.0
- core-v1.4.0
- core-v1.3.0
- core-v1.2.0
- core-v1.1.0
- common-utils-v1.12.0
- common-utils-v1.11.0
- common-utils-v1.10.0
- common-utils-v1.9.1
- common-utils-v1.9.0
- common-utils-v1.8.0
- common-utils-v1.7.2
- common-utils-v1.7.1
- common-utils-v1.7.0
- common-utils-v1.6.1
- common-utils-v1.6.0
- common-utils-v1.5.0
- common-utils-v1.4.1
- common-utils-v1.4.0
- common-utils-v1.3.0
- common-utils-v1.2.0
- common-hooks-v1.7.0
- common-hooks-v1.6.1
- common-hooks-v1.6.0
- common-hooks-v1.5.0
- common-hooks-v1.4.0
- common-hooks-v1.3.0
- common-hooks-v1.2.0
- common-hooks-v1.1.0
- common-const-v1.16.0
- common-const-v1.15.1
- common-const-v1.15.0
- common-const-v1.14.0
- common-const-v1.13.0
- common-const-v1.12.2
- common-const-v1.12.1
- common-const-v1.12.0
- common-const-v1.11.0
- common-const-v1.10.1
- common-const-v1.10.0
- common-const-v1.9.0
- common-const-v1.8.0
- common-const-v1.7.0
- common-const-v1.6.2
- common-const-v1.6.1
- common-const-v1.6.0
- common-const-v1.5.0
- common-const-v1.4.0
- common-const-v1.3.1
- common-const-v1.3.0
- common-const-v1.2.0
- balances-and-allowances-v1.2.0
- balances-and-allowances-v1.1.1
- balances-and-allowances-v1.1.0
- balances-and-allowances-v1.0.0
- assets-v1.13.0
- assets-v1.12.0
- assets-v1.11.0
- assets-v1.10.0
- assets-v1.9.0
- assets-v1.8.0
- assets-v1.7.0
- assets-v1.6.0
- assets-v1.5.0
- assets-v1.4.1
- assets-v1.4.0
- assets-v1.3.0
- assets-v1.2.0
- analytics-v1.10.0
- analytics-v1.9.0
- analytics-v1.8.0
- analytics-v1.7.0
- analytics-v1.6.0
- analytics-v1.5.0
- analytics-v1.4.0
- analytics-v1.3.0
- analytics-v1.2.0
1 parent
55f02b2
commit 7477bc0
Showing
4 changed files
with
143 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
114 changes: 114 additions & 0 deletions
114
apps/cowswap-frontend/src/cow-react/sentry/beforeSend.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import * as Sentry from '@sentry/react' | ||
import { ErrorEvent as SentryErrorEvent } from '@sentry/types' | ||
|
||
export function beforeSend(event: SentryErrorEvent, _hint: Sentry.EventHint) { | ||
if (shouldIgnoreErrorBasedOnExtra(event)) { | ||
return null | ||
} else if (shouldIgnoreErrorBasedOnBreadcrumbs(event)) { | ||
return null | ||
} else { | ||
return event | ||
} | ||
} | ||
|
||
/** | ||
* Ignore sentry errors that are unhandled exceptions and have extra serialized that similar to: | ||
* | ||
* { | ||
* code: -32000, | ||
* message: header not found | ||
* } | ||
*/ | ||
function shouldIgnoreErrorBasedOnExtra(error: SentryErrorEvent): boolean { | ||
const serialized = error.extra?.__serialized__ | ||
|
||
return Boolean( | ||
serialized && | ||
typeof serialized === 'object' && | ||
'code' in serialized && | ||
serialized.code && | ||
typeof serialized.code === 'number' && | ||
EXTRA_ERROR_CODES_TO_IGNORE.has(serialized.code) | ||
) | ||
} | ||
|
||
const EXTRA_ERROR_CODES_TO_IGNORE = new Set([-32000, 4001, -32603]) | ||
|
||
/** | ||
* Detects whether given error is a load failed error | ||
* | ||
* Adapted from https://gist.github.com/jeengbe/4bc86f05a41a1831e6abf2369579cc7a | ||
*/ | ||
function shouldIgnoreErrorBasedOnBreadcrumbs(error: SentryErrorEvent): boolean { | ||
const exception = error.exception?.values?.[0] | ||
const breadcrumbs = error.breadcrumbs | ||
|
||
if ( | ||
!exception?.type || | ||
!breadcrumbs || | ||
!isTypeError(exception.type, exception?.value) || | ||
!isUnhandledRejectionError(exception.type) | ||
) { | ||
return false | ||
} | ||
|
||
return searchBreadcrumbs(breadcrumbs, [isFetchError, isMetamaskRpcError]) | ||
} | ||
|
||
function isTypeError(type: string, value: string | undefined): boolean { | ||
return !!value && type === 'TypeError' && TYPE_ERROR_FETCH_FAILED_VALUES.has(value) | ||
} | ||
|
||
function isUnhandledRejectionError(type: string): boolean { | ||
return type === 'UnhandledRejection' | ||
} | ||
|
||
function searchBreadcrumbs(breadcrumbs: Sentry.Breadcrumb[], checkBreadcrumbs: CheckBreadcrumb[]) { | ||
const now = Date.now() | ||
|
||
// We go from the back since the last breadcrumb is most likely the erroneous one | ||
for (let i = breadcrumbs.length - 1; i >= 0; i--) { | ||
const breadcrumb = breadcrumbs[i] | ||
if (!breadcrumb) continue | ||
|
||
// We only need to check the last 3s of breadcrumbs as any earlier breadcrumbs are definitely unrelated | ||
if (breadcrumb.timestamp && now - breadcrumb.timestamp * 1000 > 3000) { | ||
break | ||
} | ||
|
||
if (checkBreadcrumbs.some((fn) => fn(breadcrumb))) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
type CheckBreadcrumb = (breadcrumb: Sentry.Breadcrumb) => boolean | ||
|
||
const TYPE_ERROR_FETCH_FAILED_VALUES = new Set([ | ||
'Failed to fetch', | ||
'NetworkError when attempting to fetch resource.', | ||
'Load failed', | ||
]) | ||
|
||
function isFetchError(breadcrumb: Sentry.Breadcrumb): boolean { | ||
if (breadcrumb.level !== 'error' || (breadcrumb.category !== 'xhr' && breadcrumb.category !== 'fetch')) { | ||
return false | ||
} | ||
|
||
const url = breadcrumb.data?.url as string | undefined | ||
if (!url) return false | ||
|
||
return URLS_TO_IGNORE_FETCH_ERRORS.test(url) | ||
} | ||
|
||
const URLS_TO_IGNORE_FETCH_ERRORS = | ||
/(twnodes\.com)|(assets\/cow-no-connection)|(api\.blocknative\.com)|(api\.country\.is)|(nodereal\.io)|(wallet\.coinbase\.com)|(cowprotocol\/cowswap-banner)/i | ||
|
||
function isMetamaskRpcError(breadcrumb: Sentry.Breadcrumb): boolean { | ||
if (breadcrumb.level !== 'error' || !breadcrumb.message) { | ||
return false | ||
} | ||
return /MetaMask.*RPC Error/i.test(breadcrumb.message) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { environmentName } from '@cowprotocol/common-utils' | ||
|
||
import * as Sentry from '@sentry/react' | ||
|
||
import { SENTRY_IGNORED_GP_QUOTE_ERRORS } from 'api/gnosisProtocol/errors/QuoteError' | ||
|
||
import { beforeSend } from './beforeSend' | ||
|
||
// eslint-disable-next-line @nx/enforce-module-boundaries | ||
import pkg from '../../../package.json' | ||
|
||
const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN | ||
const SENTRY_TRACES_SAMPLE_RATE = process.env.REACT_APP_SENTRY_TRACES_SAMPLE_RATE | ||
|
||
if (SENTRY_DSN) { | ||
Sentry.init({ | ||
dsn: process.env.REACT_APP_SENTRY_DSN, | ||
integrations: [new Sentry.BrowserTracing()], | ||
release: 'CowSwap@v' + pkg.version, | ||
environment: environmentName, | ||
ignoreErrors: [...SENTRY_IGNORED_GP_QUOTE_ERRORS, `Can't find variable: bytecode`], | ||
beforeSend, | ||
// Set tracesSampleRate to 1.0 to capture 100% | ||
// of transactions for performance monitoring. | ||
// We recommend adjusting this value in production | ||
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE ? Number(SENTRY_TRACES_SAMPLE_RATE) : 1.0, | ||
}) | ||
} |