Sentryを使用したReactアプリのエラーの追跡



今日は、Reactアプリでのリアルタイムのエラー追跡について説明します。フロントエンドアプリケーションは通常、バグ追跡には使用されません。一部の企業は、ドキュメントやテストなどの後でバグ追跡に戻ることで、バグ追跡を延期することがよくあります。ただし、製品をより良いものに変更できる場合は、それを実行してください。



1.なぜセントリーが必要なのですか?



制作中のバグの追跡に興味があると思います



これでは不十分だと思いますか?



では、詳細を見てみましょう。



開発者にSentryを使用する主な理由:



  • バグのあるコードを展開するリスクを排除します
  • コードテストにおけるQA支援
  • 問題の迅速な通知を受け取る
  • エラーをすばやく修正する機能
  • 管理パネルでエラーを便利に表示する
  • ユーザー/ブラウザセグメントによるエラーの並べ替え


プロジェクトのCEO /リードの主な理由



  • お金の節約(Sentryはサーバーにインストールできます)
  • ユーザーフィードバックの取得
  • プロジェクトの何が問題になっているのかをリアルタイムで理解する
  • あなたのアプリケーションで人々が抱えている問題の数を理解する
  • 開発者が間違いを犯した場所を見つけるのを手伝ってください


, . , Sentry.



.



?





Sentry?



Sentry – , , . , . Sentry JavaScript, Node, Python, PHP, Ruby, Java .





2.



  • Sentry . , . ( Sentry )
  • . ( React. « »)




. , Sentry , :



import * as Sentry from '@sentry/browser';
// Sentry.init({
//  dsn: "<https://63bbb258ca4346139ee533576e17ac46@sentry.io/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 , , . . , . , !



3. React Sentry



npm .



npm i @sentry/browser


Sentry :



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


DSN Projects -> Settings -> Client Keys. .





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


4.



API Deezer. . . "undefined"



, console.log user.email. : Uncaught TypeError ( email) - . Javascript.



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


:



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://fc0edcf6927a4397855797a033f04085@sentry.io/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);


.









Whoo-hoo!





, .





. , , , . ReactJS, .



, , .



. , Dmitry Nozhenko source map. , Dmitry Nozhenko, .



5. Sentry API



. javascript . , XHR?



Sentry . api.



Sentry.captureException(err)


, , , , . .



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": "john.doe@example.com"})
          .setLevel("Error")
      );
      return Sentry.captureException(err);
    }

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


API catch.



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);
};


api.



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));
      }
    });
};


:



  • setLevel sentry. — ‘fatal’, ‘error’, ‘warning’, ‘log’, ‘info, ‘debug’, ‘critical’).
  • setUser (id, , . .).
  • setExtra , , , .


バグに関するユーザーフィードバックを取得する場合は、showReportDialog関数を使用する必要があります。



Sentry.showReportDialog();


出力:



今日は、SentryをReactアプリに統合する1つの方法について説明しました。



セントリー経由のテレグラムチャット




All Articles