Tracking errors in a React app with Sentry

Tracking errors in a React app with Sentry

Today I'm going to walk you through real-time error tracking in a React app. The frontend application is not typically used for bug tracking. Some companies often put aside bug tracking, returning to it after documentation, tests, and so on. However, if you can change your product for the better, then just do it!

1. Why do you need Sentry?

I'm assuming you're interested in bug tracking during production.

Do you think this is not enough?

Okay, let's look at the details.

Top Reasons to Use Sentry for Developers:

  • Allows you to get rid of risks when deploying code with errors
  • Help QA in code testing
  • Get quick problem notifications
  • Ability to quickly fix errors
  • Getting a convenient display of errors in the admin panel
  • Sort errors by user/browser segment

Main reasons for CEO / Lead project

  • Save money (Sentry can be installed on your servers)
  • Get user feedback
  • Understanding what's wrong with your project in real time
  • Understanding the number of problems people have with your app
  • Help in finding places where your developers made a mistake

I think the developers would be interested in this article in the first place. You can also use this list of reasons to convince your boss to integrate Sentry.

Be careful with the last item on the business list.

Are you already interested?

Tracking errors in a React app with Sentry

What is Sentry?

Sentry is an open source bug tracking application that helps developers track and fix crashes in real time. Don't forget that the app also allows you to increase efficiency and improve user experience. Sentry supports JavaScript, Node, Python, PHP, Ruby, Java and other programming languages.

Tracking errors in a React app with Sentry

2. Login and create a project

  • Open your Sentry account. You may need to sign in. (Please note that Sentry can be installed on your servers)
  • The next step is to create a project
  • Select your language from the list. (We're going to choose React. Click "Create Project")

Tracking errors in a React app with Sentry

Set up your application. You can see a basic example of how to integrate Sentry into a container below:

import * as Sentry from '@sentry/browser';
// Sentry.init({
//  dsn: "<https://[email protected]/1432138>"
// });
// should have been called before using it here
// ideally before even rendering your react app 

class ExampleBoundary extends Component {
    constructor(props) {
        super(props);
        this.state = { error: null };
    }

    componentDidCatch(error, errorInfo) {
      this.setState({ error });
      Sentry.withScope(scope => {
        Object.keys(errorInfo).forEach(key => {
          scope.setExtra(key, errorInfo[key]);
        });
        Sentry.captureException(error);
      });
    }

    render() {
        if (this.state.error) {
            //render fallback UI
            return (
              <a onClick={() => Sentry.showReportDialog()}>Report feedback</a>
            );
        } else {
            //when there's not an error, render children untouched
            return this.props.children;
        }
    }
}

Sentry has a helpful wizard to help you understand what you should do next. You can follow the steps below. I want to show you how to create your first error handler. Great, we have created a project! Let's move on to the next step

3. Integrating React and Sentry

You must install the npm package in your project.

npm i @sentry/browser

Initialize Sentry in your container:

Sentry.init({
 // dsn: #dsnUrl,
});

The DSN is located in Projects -> Settings -> Client Keys. You can find client keys in the search bar.

Tracking errors in a React app with Sentry

componentDidCatch(error, errorInfo) {
  Sentry.withScope(scope => {
    Object.keys(errorInfo).forEach(key => {
      scope.setExtra(key, errorInfo[key]);
    });
    Sentry.captureException(error);
 });
}

4. Tracking the first error

For example, I used a simple music application with the Deezer API. You can see it here. We need to create an error. One way is to access the "undefined" property

We need to create a button that calls console log с user.email. After this action, we should receive an error message: Uncaught TypeError (Cannot read property from undefined email) due to the absence of a user object. You can also use javascript exception.

<button type="button" onClick={() => console.log(user.email)}>   
  Test Error button 
</button>

The whole container looks like this:

import React, { Component } from "react";
import { connect } from "react-redux";
import { Input, List, Skeleton, Avatar } from "antd";
import * as Sentry from "@sentry/browser";
import getList from "../store/actions/getList";

const Search = Input.Search;

const mapState = state => ({
  list: state.root.list,
  loading: state.root.loading
});

const mapDispatch = {
  getList
};

class Container extends Component {
  constructor(props) {
    super(props);

    Sentry.init({
      dsn: "https://[email protected]/1417586",
    });
  }

  componentDidCatch(error, errorInfo) {
    Sentry.withScope(scope => {
      Object.keys(errorInfo).forEach(key => {
        scope.setExtra(key, errorInfo[key]);
      });
      Sentry.captureException(error);
    });
  }
  render() {
    const { list, loading, getList } = this.props;
    const user = undefined;
    return (
      <div className="App">
        <button
          type="button"
          onClick={() => console.log(user.email)}
        >
          test error1
        </button>
        <div onClick={() => Sentry.showReportDialog()}>Report feedback1</div>
        <h1>Music Finder</h1>
        <br />
        <Search onSearch={value => getList(value)} enterButton />
        {loading && <Skeleton avatar title={false} loading={true} active />}
        {!loading && (
          <List
            itemLayout="horizontal"
            dataSource={list}
            locale={{ emptyText: <div /> }}
            renderItem={item => (
              <List.Item>
                <List.Item.Meta
                  avatar={<Avatar src={item.artist.picture} />}
                  title={item.title}
                  description={item.artist.name}
                />
              </List.Item>
            )}
          />
        )}
      </div>
    );
  }
}

export default connect(
  mapState,
  mapDispatch
)(Container);

After integrating this button, you should test it in the browser.

Tracking errors in a React app with Sentry

We have our first error

Tracking errors in a React app with Sentry

Whoo-hoo!

Tracking errors in a React app with Sentry

If you click on the header error, you will see the stack trace.

Tracking errors in a React app with Sentry

The messages look bad. Of course, we have seen error messages without understanding where this code is. By default it is about source map in ReactJS because they are not configured.

I would also like to provide instructions for setting up the source map, but that would make this post a lot longer than I intended.

You can study this topic here. If you are interested in this article, Dmitry Nozhenko will publish the second part about source map integration. So click more likes and subscribe to Dmitry Nozhenkonot to miss the second part.

5. Use Sentry with endpoint API

OK. We have covered the javascript exception in the previous paragraphs. However, what do we do with XHR errors?

Sentry also has custom error handling. I used it for api bug tracking.

Sentry.captureException(err)

You can customize the bug name, level, add data, unique user data via your app, email, etc.

superagent
  .get(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${query}`)
  .set("X-RapidAPI-Key", #id_key)
  .end((err, response) => {
    if (err) {
      Sentry.configureScope(
        scope => scope
          .setUser({"email": "[email protected]"})
          .setLevel("Error")
      );
      return Sentry.captureException(err);
    }

    if (response) {
      return dispatch(setList(response.body.data));
    }
  });

I would like to use a generic function for the catch API.

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

export const apiCatch = (error, getState) => {
  const store = getState();
  const storeStringify = JSON.stringify(store);
  const { root: { user: { email } } } = store;

  Sentry.configureScope(
    scope => scope
      .setLevel("Error")
      .setUser({ email })
      .setExtra("store", storeStringify)
  );
    // Sentry.showReportDialog(); - If you want get users feedback on error
  return Sentry.captureException(error);
};

Import this function in api call.

export default query => (dispatch, getState) => {
  superagent
    .get(`https://deezerdevs-deezer.p.rapidapi.com/search?q=${query}`)
    .set("X-RapidAPI-Key", #id_key)
    .end((error, response) => {
      if (error) {
        return apiCatch(error, getState)
      }

      if (response) {
        return dispatch(setList(response.body.data));
      }
    });
};

Let's check the methods:

  • setLevel allows you to insert a level error in the sentry dashboard. It has properties - 'fatal', 'error', 'warning', 'log', 'info, 'debug', 'critical').
  • setUser helps to save any user data (id, email address, payment plan, etc.).
  • setExtra allows you to set any data that you need, for example, a store.

If you want user feedback on a bug, you should use the showReportDialog function.

Sentry.showReportDialog();

Conclusion:

Today we described one of the ways to integrate Sentry into a React application.

β†’ Telegram chat by Sentry

Source: habr.com

Add a comment