thraizz / blog-comments

Comments for my blog :)
https://lakur.tech
0 stars 0 forks source link

blog/2022/12/16/generating-meaningful-issues-in-sentry-with-react-query-+-axios/ #4

Open utterances-bot opened 11 months ago

utterances-bot commented 11 months ago

Meaningful Sentry issues with react-query + axios - Lakur

This post shows how to enrich axios errors when using react-query and how to handle them on a global level.

https://lakur.tech/2022/12/16/generating-meaningful-issues-in-sentry-with-react-query-+-axios/

oxatruchdev commented 11 months ago

This was extremely useful, thanks so much for sharing!

bryanltobing commented 11 months ago

after adding all these, i still don't get meaningful info. any idea?

queryClient

export const queryClient = new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) => {
      withScope((scope) => {
        scope.setContext('query', { queryHash: query.queryHash });
        scope.setFingerprint([query.queryHash.replaceAll(/[0-9]/g, '0')]);
        captureException(error);
      });

      const withErrorToast =
        query.meta?.withErrorToast === undefined ? true : query.meta?.withErrorToast;

      if (!withErrorToast && process.env.EXPO_PUBLIC_ENV_NAME === 'PROD') {
        return;
      }

      const errorMessage = getHttpErrorMessages(error)?.[0].message;
      Toast.show({
        type: 'error',
        text1: errorMessage,
        visibilityTime: 3000,
      });
    },
  }),
  mutationCache: new MutationCache({
    onError: (error, _var, _context, mutation) => {
      withScope((scope) => {
        scope.setContext('mutation', {
          mutationId: mutation.mutationId,
          variables: mutation.state.variables,
        });
        if (mutation.options.mutationKey) {
          scope.setFingerprint(
            // Duplicate to prevent modification
            Array.from(mutation.options.mutationKey) as string[],
          );
        }
        captureException(error);
      });

      const withErrorToast =
        mutation.meta?.withErrorToast === undefined ? true : mutation.meta?.withErrorToast;

      if (!withErrorToast && process.env.EXPO_PUBLIC_ENV_NAME === 'PROD') {
        return;
      }

      const errorMessage = getHttpErrorMessages(error)?.[0].message;
      Toast.show({
        type: 'error',
        text1: errorMessage,
        visibilityTime: 3000,
      });
    },
  }),
});
export const init = () => {
  return Sentry.init({
    dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
    environment: process.env.EXPO_PUBLIC_ENV_NAME,
    /**
     * Set to true for local debugging
     * Set back to false when pushing commits
     */
    enableInExpoDevelopment: true,
    /**
     * If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production
     */
    debug: __DEV__,
    tracesSampleRate: 1.0,
    integrations: [
      new Sentry.Native.ReactNativeTracing({
        shouldCreateSpanForRequest: (url) => {
          return !__DEV__ || !url.startsWith(`http://${Constants?.expoConfig?.hostUri}/logs`);
        },
      }),
      new ExtraErrorDataIntegration(),
    ],
  });
};
navignaw commented 3 months ago

The fingerprinting is really cool, but I found that it doesn't group errors as well as I'd like. For example, my app frequently makes requests to an endpoint GET /resources/<resource_uuid>/ where resource_uuid is an arbitrary UUID. However, the queryHash is unable to map all of them to the same value.

I suspect that queryHash.replaceAll(/[0-9]/g, "0") is attempting to do this for integer value ids only, but it fails because a UUID contains hex and hyphens? Perhaps we need a more complex regex matcher that replaces any UUID, like this stackoverflow suggests? https://stackoverflow.com/a/6640851

Here's something I came up with:

function canonicalizeQueryHash(queryHash: string): string {
  return (
    queryHash
      // Numbers wrapped in forward-slashes, or at the end of the string
      .replaceAll(/\/[0-9]+(\/|$)/g, '/<id>$1')
      .replaceAll(
        // UUIDs wrapped in forward-slashes, or at the end of the string
        /\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(\/|$)/g,
        '/<uuid>$1'
      )
  )
}