Skip to content

Latest commit

 

History

History
257 lines (202 loc) · 8.48 KB

File metadata and controls

257 lines (202 loc) · 8.48 KB

Sentry

What is it?

Sentry is an open-source error monitoring and crash reporting tool used by developers and organizations to track and debug software errors and exceptions in real-time. It is designed to help developers identify and fix issues in their applications quickly.

With Sentry, developers can integrate the tool into their applications and collect data on errors, exceptions, and crashes that occur during runtime. When an error or exception is detected, Sentry captures relevant information such as the stack trace, environment variables, and user context, providing valuable insights into the root cause of the issue.

The captured data is then aggregated and displayed in the Sentry dashboard, where developers can view and analyze the errors, track their occurrence frequency, and prioritize them based on their impact. Sentry also provides features such as issue assignment, notifications, and release tracking, enabling teams to collaborate and resolve issues efficiently.

How to use Sentry in React applications

To use Sentry in a React application, you can follow these general steps:

  1. Check out the official guide of creating a new project in Sentry admin panel.

  2. Configure alert rules for your project.

Alerts configuring

  • Click to the "Create alert" button and set conditions for the new alert rule.

    Create alert

  • Create a rule of alerts for non-production environments. Note that here you could configure notifications in Slack channels from your organizations.

    Non-prod envs

  • Create a rule of alerts for the production environment.

    Prod env

  1. Get the project DSN key:

Create alert

  1. Add this key in your .env file.
  2. Add other Sentry env variables to your .env file:
REACT_APP_SENTRY_DSN=
REACT_APP_SENTRY_AUTH_TOKEN=
REACT_APP_SENTRY_ORG=your-organization-name
REACT_APP_SENTRY_PROJECT=your-project-name
REACT_APP_ENV=local // make this env variable dynamic for different environments
  1. Check out Sentry configuration guide for React applications.

  2. Configure Sentry in your index.tsx file:

import * as Sentry from "@sentry/react";

// define your environment names on the project, where Sentry should be enabled
const enabledForEnvironments = ['development', 'staging', 'production'];

const samplesRateByEnvironment = {
  'development': 1.0, 
  'staging': 0.5, 
  'production': 0.1
}

const DEFAULT_TRACING_RATE = 0.1;

const isSentryEnabled = enabledForEnvironments.includes(ENV);

const sampleRate = samplesRateByEnvironment[ENV] || DEFAULT_TRACING_RATE;

Sentry.init({
  enabled: isSentryEnabled,
  release: process.env.REACT_APP_RELEASE_VERSION, // Configure this variable in your CI to make it dynamic across diffent environments
  dsn: process.env.REACT_APP_SENTRY_DSN,
  integrations: [Sentry.browserTracingIntegration()],
  environment: ENV,
  profilesSampleRate: sampleRate,
  replaysSessionSampleRate: sampleRate,
  tracesSampleRate: sampleRate,
  tracePropagationTargets: [
    // define targets to which you want propagate Sentry traces (usually API host)
    /^https:\/\/api.*\..*domain\.com.*/, 
  ],
});
  1. Configure your error boundary component:
import { Component, ErrorInfo, ReactNode } from "react";
import { withScope, captureException, SeverityLevel } from "@sentry/react";
import { Error } from "@pages";

interface IProps {
  children: ReactNode;
}

interface IState {
  error: null | Error;
}

export class ErrorBoundary extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.state = { error: null };

    this.clearState = this.clearState.bind(this);
  }

  public componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
    this.setState({ error });
    withScope((scope) => {
      scope.setTag("Custom-Tag", "ErrorBoundary");
      scope.setLevel("Error" as SeverityLevel);
      Object.keys(errorInfo).forEach((key) => {
        scope.setExtra(key, errorInfo[key as keyof ErrorInfo]);
      });
      captureException(error);
    });
  }

  public clearState() {
    this.setState({ error: null });
  }

  public render(): ReactNode {
    const { error } = this.state;

    if (error) {
      return <Error clearState={this.clearState} />;
    }
    const { children } = this.props;
    return children;
  }
}
  1. You can also create a helper function reportError for catching errors in Sentry:
interface IReportError {
  error: string | Error;
  tagKey?: string;
  tagValue?: string;
  extraInfo?: Extras;
}

export const reportError = ({
  error,
  tagKey,
  tagValue,
  extraInfo,
}: IReportError) => {
  withScope((scope) => {
    if (tagKey && tagValue) {
      scope.setTag(tagKey, tagValue);
    }
    if (extraInfo) {
      scope.setExtras(extraInfo);
    }
    scope.setLevel("Error" as SeverityLevel);

    captureException(error);
  });
};
  1. After that, you can call it whenever you need in your code:

    • In Axios interceptors:

        Axios.interceptors.response.use(undefined, (error) => {
          reportError({
            error: `Request failed (${error.response.config.method}/ ${error.response.config.url})`,
            extraInfo: error.response.config.data
              ? JSON.parse(error.response.config.data)
              : {},
          });
      
          const { title, description } = parseServerException(error);
          displayToastError(title, description);
          return Promise.reject(error);
        });
    • In other places in your app:

    try {
      await uploadFileToS3(file, uploadURL).then(() =>
        setValue(fieldName, imageKey, { shouldDirty: true })
      );
    } catch {
      reportError({ error: "Image file uploading error" });
    }
  2. To enable readable stack traces in your Sentry errors, you need to upload your source maps to Sentry. Check out guides of how to upload source maps.

  3. If you use craco on your project, feel free to use this config:

 const CracoAlias = require("craco-alias");
 const SentryWebpackPlugin = require("@sentry/webpack-plugin");

 module.exports = {
   devtool: "source-map",
   plugins: [
     {
       plugin: CracoAlias,
       options: {
         source: "tsconfig",
         baseUrl: ".",
         tsConfigPath: "./tsconfig.path.json",
       },
     },
     {
       plugin: SentryWebpackPlugin,
       options: {
         org: process.env.REACT_APP_SENTRY_ORG,
         project: process.env.REACT_APP_SENTRY_PROJECT,
         include: "build/static/",
         urlPrefix: "~/static/",
         authToken: process.env.SENTRY_AUTH_TOKEN,
         release: process.env.REACT_APP_RELEASE_VERSION,
       },
     },
   ],
 };

 export {};
  1. Here is an example of CI job (CircleCI) for uploading source maps to Sentry:
  notify-sentry-deploy:
    executor: app-executor
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run: |
          cat bash.env > $BASH_ENV
      - run: |
          printenv REACT_APP_RELEASE_VERSION
          printenv REACT_APP_ENV
      - run:
          name: Create release and notify Sentry of deploy
          command: |
            curl -sL https://sentry.io/get-cli/ | bash
            sentry-cli releases -o $REACT_APP_SENTRY_ORG new -p $SENTRY_PROJECT $REACT_APP_RELEASE_VERSION
            sentry-cli releases set-commits $REACT_APP_RELEASE_VERSION --auto --ignore-missing
            sentry-cli releases files $REACT_APP_RELEASE_VERSION upload-sourcemaps "~/static/"
            sentry-cli releases finalize $REACT_APP_RELEASE_VERSION
            sentry-cli releases deploys $REACT_APP_RELEASE_VERSION new -e $REACT_APP_ENV