Sentry remote bug monitoring in React front-end applications

We are looking into using Sentry with React.

Sentry remote bug monitoring in React front-end applications

This article is part of a series starting with a Sentry error message with an example: Part 1.

React implementation

First we need to add a new Sentry project for this application; from the Sentry website. In this case, we choose React.

We are re-implementing our two buttons, Hello and Error, with React. We start by creating our starter application:

npx create-react-app react-app

We then import the Sentry package:

yarn add @sentry/browser

and initialize it:

react-app/src/index.js

...
import * as Sentry from '@sentry/browser';

const RELEASE = '0.1.0';
if (process.env.NODE_ENV === 'production') {
  Sentry.init({
    dsn: 'https://[email protected]/1289887',
    release: RELEASE,
  });
}
...

Observations:

  • During development, we have other mechanisms for monitoring issues, such as the console, so we only enable Sentry for production builds.

We then implement our Hello and Error buttons and add them to the application:

react-app/src/hello.js

import React, { Component } from 'react';
import * as Sentry from '@sentry/browser';

export default class Hello extends Component {
  state = {
    text: '',
  };
  render() {
    const { text } = this.state;
    return (
      <div>
        <button
          onClick={this.handleClick}
        >
          Hello
        </button>
        <div>{text}</div>
      </div>
    )
  }

  handleClick = () => {
    this.setState({
      text: 'Hello World',
    });
    try {
      throw new Error('Caught');
    } catch (err) {
      if (process.env.NODE_ENV !== 'production') {
        return;
      }
      Sentry.captureException(err);
    }
  }
}

react-app/src/MyError.js

import React, { Component } from 'react';

export default class MyError extends Component {
  render() {
    return (
      <div>
        <button
          onClick={this.handleClick}
        >
          Error
        </button>
      </div>
    )
  }

  handleClick = () => {
    throw new Error('Uncaught');
  }
}

react-app/src/app.js

...
import Hello from './Hello';
import MyError from './MyError';

class App extends Component {
  render() {
    return (
      <div className="App">
        ...
        <Hello />
        <MyError />
      </div>
    );
  }
}

export default App;

Problem (Source Maps)

We can test Sentry with a production build by typing:

yarn build

and from build folder type:

npx http-server -c-1

The problem we immediately run into is that the Sentry error entries refer to line numbers in the reduced package; not very helpful.

Sentry remote bug monitoring in React front-end applications

The Sentry service explains this by pulling the source maps for the reduced batch after receiving an error. In this case, we are running from localhost (not accessible by the Sentry service).

Solutions (Source Maps)

The solution to this problem is to run the application from a public web server. One simple answer button to use the GitHub Pages service (free). The steps to use are usually the following:

  1. Copy the contents of the folder build to folder docs in the root directory of the repository.

  2. Turn on GitHub Pages in the repository (from GitHub) to use the docs folder in master vetvi

  3. Push changes to GitHub

Note: after I figured out what I need to use create-create-app home page function to launch the application. It boiled down to adding the following to package.json:

"homepage": "https://larkintuckerllc.github.io/hello-sentry/"

The final version of the running application is available at:

https://larkintuckerllc.github.io/hello-sentry/

Illustration of Caught Bugs

Let's go through clicking the Hello button.

Sentry remote bug monitoring in React front-end applications

With an error appearing like this:

Sentry remote bug monitoring in React front-end applications

Observations:

  • This bug report couldn't be clearer, BRAVO.

Illustration of Unreported Errors

Likewise, let's go through the button press Error.

Sentry remote bug monitoring in React front-end applications

With an error appearing like this:

Sentry remote bug monitoring in React front-end applications

Better unhandled error handling (rendering)

Introduction of Error Boundaries

A JavaScript error in the user interface should not break the entire application. To solve this problem for React users, React 16 introduces a new concept of "error border".

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that has crashed. Error boundaries catch errors at render time, in lifecycle methods, and in the constructors of the entire tree below them.

...

New behavior for undetected errors

This change is important. As of React 16, errors that are not caught by any error boundary will cause the entire React component tree to be unmounted.

β€” Dan Abramov- Error Handling in React 16

An important clarification, which took me a while before I figured it out, is that the above behavior only works with errors thrown in the render method (or more likely any of the lifecycle methods). For example, using error borders wouldn't do any good with our button Error; this error was in the click handler.

Let's create an example render error and then use error bounds to handle the error more gracefully.

react-app/src/MyRenderError

import React, { Component } from 'react';

export default class MyRenderError extends Component {
  state = {
    flag: false,
  };
  render() {
    const { flag } = this.state;
    return (
      <div>
        <button
          onClick={this.handleClick}
        >
          Render Error
        </button>
        { flag && <div>{flag.busted.bogus}</div> }
      </div>
    )
  }

  handleClick = () => {
    this.setState({
      flag: true,
    });
  }
}

Observation:

  • When you press the button, React will be displayed flag.busted.bogus, which generates an error

  • Without an error boundary, the entire component tree will be unmounted

We then write our error boundary code (uses the new lifecycle method componentDidCatch); this is essentially the example given in Dan Abramov's article:

react-app/src/ErrorBoundary.js

import React, { Component } from 'react';
import * as Sentry from '@sentry/browser';

export default class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(err, info) {
    this.setState({ hasError: true });
    Sentry.captureException(err);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

Finally, we use this component:

react-app/src/app.js

...
import MyRenderError from './MyRenderError';

class App extends Component {
  render() {
    return (
      <ErrorBoundary>
        <div className="App">
          ...
        </div>
      </ErrorBoundary>
    );
  }
}
...

However, pressing the Render Error button displays the fallback UI and reports the error to Sentry.

Sentry remote bug monitoring in React front-end applications

Sentry remote bug monitoring in React front-end applications

Completion

I hope you found it useful.

PS Link to the original

PS Telegram chat by Sentry https://t.me/sentry_ru

Source: habr.com

Add a comment