αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αžαŸ’αž„αŸƒαž“αŸαŸ‡αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž”αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž’αŸ†αž–αžΈαž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž€αŸ’αž“αž»αž„αž–αŸαž›αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„αž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αŸ” αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž•αŸ’αž“αŸ‚αž€αžαžΆαž„αž˜αž»αžαž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαž‡αžΆαž’αž˜αŸ’αž˜αžαžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž‘αŸαŸ” αž€αŸ’αžšαž»αž˜αž αŸŠαž»αž“αž˜αž½αž™αž…αŸ†αž“αž½αž“αžαŸ‚αž„αžαŸ‚αž”αž·αž‘αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸ αžŠαŸ„αž™αžαŸ’αžšαž›αž”αŸ‹αž‘αŸ…αžœαžΆαžœαž·αž‰αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž―αž€αžŸαžΆαžš αž€αžΆαžšαž’αŸ’αžœαžΎαžαŸαžŸαŸ’αžαŸ”αž›αŸ” αž™αŸ‰αžΆαž„β€‹αžŽαžΆβ€‹αž˜αž·αž‰ αž”αŸ’αžšαžŸαž·αž“β€‹αž”αžΎβ€‹αž’αŸ’αž“αž€β€‹αž’αžΆαž…β€‹αž•αŸ’αž›αžΆαžŸαŸ‹β€‹αž”αŸ’αžαžΌβ€‹αžšβ€‹αž•αž›αž·αžαž•αž›β€‹αžšαž”αžŸαŸ‹β€‹αž’αŸ’αž“αž€β€‹αž±αŸ’αž™β€‹αž€αžΆαž“αŸ‹β€‹αžαŸ‚β€‹αž›αŸ’αž’β€‹αž”αŸ’αžšαžŸαžΎαžšβ€‹αž“αŸ„αŸ‡β€‹αž‚αŸ’αžšαžΆαž“αŸ‹β€‹αžαŸ‚β€‹αž’αŸ’αžœαžΎβ€‹αžœαžΆβ€‹!

1. αž αŸαžαž»αž’αŸ’αžœαžΈαž”αžΆαž“αž‡αžΆαž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αžΆαžš Sentry?

αžαŸ’αž‰αž»αŸ†αžŸαž“αŸ’αž˜αžαŸ‹αžαžΆαž’αŸ’αž“αž€αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž’αŸ†αž‘αž»αž„αž–αŸαž›αž•αž›αž·αž

αžαžΎαž’αŸ’αž“αž€αž‚αž·αžαžαžΆαž“αŸαŸ‡αž˜αž·αž“αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αž‘αŸ?

αž˜αž·αž“αž’αžΈαž‘αŸ αžαŸ„αŸ‡αž˜αžΎαž›αž–αŸαžαŸŒαž˜αžΆαž“αž›αž˜αŸ’αž’αž·αžαŸ”

αž αŸαžαž»αž•αž›αž€αŸ†αž–αžΌαž›αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ SentryαŸ–

  • αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž‡αŸ€αžŸαžœαžΆαž„αž αžΆαž“αž·αž—αŸαž™αž“αŸ…αž–αŸαž›αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž€αžΌαžŠαžŠαŸ‚αž›αž˜αžΆαž“αž€αŸ†αž αž»αžŸ
  • αž‡αž½αž™ QA αž‡αžΆαž˜αž½αž™αž€αžΆαžšαž’αŸ’αžœαžΎαžαŸαžŸαŸ’αžαž€αžΌαžŠ
  • αž‘αž‘αž½αž›αž”αžΆαž“αž€αžΆαžšαž‡αžΌαž“αžŠαŸ†αžŽαžΉαž„αžšαž αŸαžŸαž’αŸ†αž–αžΈαž”αž‰αŸ’αž αžΆ
  • αžŸαž˜αžαŸ’αžαž—αžΆαž–αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ‚αž€αŸ†αž αž»αžŸαž™αŸ‰αžΆαž„αž†αžΆαž”αŸ‹αžšαž αŸαžŸ
  • αž‘αž‘αž½αž›αž”αžΆαž“αž€αžΆαžšαž”αž„αŸ’αž αžΆαž‰αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž“αŸƒαž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž•αŸ’αž‘αžΆαŸ†αž„αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„
  • αžαž˜αŸ’αžšαŸ€αž”αž€αŸ†αž αž»αžŸαžαžΆαž˜αž•αŸ’αž“αŸ‚αž€αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹/αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž»αž€αžšαž€

αž αŸαžαž»αž•αž›αž…αž˜αŸ’αž”αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αž“αžΆαž™αž€αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·/αž’αŸ’αž“αž€αžŠαžΉαž€αž“αžΆαŸ†

  • αžŸαž“αŸ’αžŸαŸ†αž”αŸ’αžšαžΆαž€αŸ‹ (Sentry αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ†αž‘αžΎαž„αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€)
  • αž‘αž‘αž½αž›αž”αžΆαž“αž˜αžαž·αž’αŸ’αž“αž€αž”αŸ’αžšαžΎ
  • αžŸαŸ’αžœαŸ‚αž„αž™αž›αŸ‹αž–αžΈαž’αŸ’αžœαžΈαžŠαŸ‚αž›αžαž»αžŸαž‡αžΆαž˜αž½αž™αž‚αž˜αŸ’αžšαŸ„αž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž€αŸ’αž“αž»αž„αž–αŸαž›αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„
  • αž€αžΆαžšαž™αž›αŸ‹αžŠαžΉαž„αž’αŸ†αž–αžΈαž…αŸ†αž“αž½αž“αž”αž‰αŸ’αž αžΆαžŠαŸ‚αž›αž˜αž“αž»αžŸαŸ’αžŸαž˜αžΆαž“αž‡αžΆαž˜αž½αž™αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”
  • αž‡αž½αž™αž’αŸ’αž“αž€αžŸαŸ’αžœαŸ‚αž„αžšαž€αž€αž“αŸ’αž›αŸ‚αž„αžŠαŸ‚αž›αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž˜αžΆαž“αž€αŸ†αž αž»αžŸ

αžαŸ’αž‰αž»αŸ†αž‚αž·αžαžαžΆαž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαž“αžΉαž„αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž›αžΎαž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡αž‡αžΆαž˜αž»αž“αžŸαž·αž“αŸ” αž’αŸ’αž“αž€αž€αŸαž’αžΆαž…αž”αŸ’αžšαžΎαž”αž‰αŸ’αž‡αžΈαž αŸαžαž»αž•αž›αž“αŸαŸ‡αžŠαžΎαž˜αŸ’αž”αžΈαž”αž‰αŸ’αž…αž»αŸ‡αž”αž‰αŸ’αž…αžΌαž›αž…αŸ…αž αŸ’αžœαžΆαž™αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž±αŸ’αž™αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž› Sentry αž•αž„αžŠαŸ‚αžšαŸ”

αžŸαžΌαž˜αž”αŸ’αžšαž™αŸαžαŸ’αž“αž‡αžΆαž˜αž½αž™αž’αžΆαžαž»αž…αž»αž„αž€αŸ’αžšαŸ„αž™αž“αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž‡αžΈαž’αžΆαž‡αžΈαžœαž€αž˜αŸ’αž˜αŸ”

αžαžΎαž’αŸ’αž“αž€αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž αžΎαž™αž¬αž“αŸ…?

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

តើ Sentry αž‡αžΆαž’αŸ’αžœαžΈ?

Sentry αž‚αžΊαž‡αžΆαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž”αŸ’αžšαž—αž–αž”αžΎαž€αž…αŸ†αž αžŠαŸ‚αž›αž‡αž½αž™αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαžαžΆαž˜αžŠαžΆαž“ αž“αž·αž„αž‡αž½αžŸαž‡αž»αž›αž€αžΆαžšαž‚αžΆαŸ†αž„αž€αŸ’αž“αž»αž„αž–αŸαž›αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„αŸ” αž€αž»αŸ†αž—αŸ’αž›αŸαž…αžαžΆαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž”αž„αŸ’αž€αžΎαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž– αž“αž·αž„αž€αŸ‚αž›αž˜αŸ’αž’αž”αž‘αž–αž·αžŸαŸ„αž’αž“αŸαž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αŸ” Sentry αž‚αžΆαŸ†αž‘αŸ’αžš JavaScript, Node, Python, PHP, Ruby, Java αž“αž·αž„αž—αžΆαžŸαžΆαžŸαžšαžŸαŸαžšαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαŸ”

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

2. αž…αžΌαž› αž“αž·αž„αž”αž„αŸ’αž€αžΎαžαž‚αž˜αŸ’αžšαŸ„αž„

  • αž”αžΎαž€αž‚αžŽαž“αžΈ Sentry αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ” αž’αŸ’αž“αž€αž”αŸ’αžšαž αŸ‚αž›αž‡αžΆαžαŸ’αžšαžΌαžœαž…αžΌαž›αŸ” (αžŸαžΌαž˜αž…αŸ†αžŽαžΆαŸ†αžαžΆ Sentry αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ†αž‘αžΎαž„αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€)
  • αž‡αŸ†αž αžΆαž“αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž‚αžΊαž”αž„αŸ’αž€αžΎαžαž‚αž˜αŸ’αžšαŸ„αž„
  • αž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž—αžΆαžŸαžΆαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž–αžΈαž”αž‰αŸ’αž‡αžΈαŸ” (αž™αžΎαž„αž“αžΉαž„αž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸ αž”αŸ’αžšαžαž·αž€αž˜αŸ’αž˜αŸ” αž…αž»αž… "αž”αž„αŸ’αž€αžΎαžαž‚αž˜αŸ’αžšαŸ„αž„")

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αž”αŸ’αžŠαžΌαžšαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αžαžΆαž˜αž”αŸ†αžŽαž„αŸ” αž§αž‘αžΆαž αžšαžŽαŸαž‡αžΆαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž“αŸƒαžšαž”αŸ€αž”αž”αž‰αŸ’αž…αžΌαž› Sentry αž‘αŸ…αž€αŸ’αž“αž»αž„αž€αž»αž„αžαžΊαž“αŸαžš αž’αžΆαž…αž˜αžΎαž›αžƒαžΎαž‰αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–

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 αž˜αžΆαž“αž’αŸ’αž“αž€αž‡αŸ†αž“αž½αž™αž€αžΆαžšαžŠαŸαž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸ αžŠαžΎαž˜αŸ’αž”αžΈαž‡αž½αž™αž’αŸ’αž“αž€αžŸαŸ’αžœαŸ‚αž„αž™αž›αŸ‹αž–αžΈαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž’αŸ’αž“αž€αž‚αž½αžšαž’αŸ’αžœαžΎαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž‘αŸ€αžαŸ” αž’αŸ’αž“αž€αž’αžΆαž…αž’αž“αž»αžœαžαŸ’αžαžαžΆαž˜αž‡αŸ†αž αžΆαž“αž‘αžΆαŸ†αž„αž“αŸαŸ‡αŸ” αžαŸ’αž‰αž»αŸ†αž…αž„αŸ‹αž”αž„αŸ’αž αžΆαž‰αž’αŸ’αž“αž€αž–αžΈαžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž€αŸ†αž αž»αžŸαžŠαŸ†αž”αžΌαž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ” αž›αŸ’αž’αžŽαžΆαžŸαŸ‹ αž™αžΎαž„αž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž‚αž˜αŸ’αžšαŸ„αž„αž˜αž½αž™! αžαŸ„αŸ‡αž”αž“αŸ’αžαž‘αŸ…αž‡αŸ†αž αžΆαž“αž”αž“αŸ’αž‘αžΆαž”αŸ‹

3. αž€αžΆαžšαžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž”αŸ’αžšαžαž·αž€αž˜αŸ’αž˜ αž“αž·αž„ Sentry

αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαžαŸ‚αžŠαŸ†αž‘αžΎαž„αž€αž‰αŸ’αž…αž”αŸ‹ npm αž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

npm i @sentry/browser

αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜ Sentry αž“αŸ…αž€αŸ’αž“αž»αž„αž’αž»αž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ–

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

DSN αž˜αžΆαž“αž‘αžΈαžαžΆαŸ†αž„αž“αŸ…αž€αŸ’αž“αž»αž„ Projects -> Settings -> Client KeysαŸ” αž’αŸ’αž“αž€αž’αžΆαž…αžŸαŸ’αžœαŸ‚αž„αžšαž€αž€αžΌαž“αžŸαŸ„αž“αŸ…αž€αŸ’αž“αž»αž„αžšαž”αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αŸ”

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

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

4. αžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαžŠαŸ†αž”αžΌαž„

αž‡αžΆαž§αž‘αžΆαž αžšαžŽαŸ αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž”αŸ’αžšαžΎαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžαž“αŸ’αžαŸ’αžšαžΈαžŸαžΆαž˜αž‰αŸ’αž‰αž‡αžΆαž˜αž½αž™ Deezer APIαŸ” αž’αŸ’αž“αž€αž’αžΆαž…αžƒαžΎαž‰αžœαžΆαŸ” αž“αŸ…αž‘αžΈαž“αŸαŸ‡. αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αž„αŸ’αž€αžΎαžαž€αŸ†αž αž»αžŸαŸ” αžœαž·αž’αžΈαž˜αž½αž™αž‚αžΊαžαŸ’αžšαžΌαžœαž…αžΌαž›αž”αŸ’αžšαžΎαž›αž€αŸ’αžαžŽαžŸαž˜αŸ’αž”αžαŸ’αžαž· "αž˜αž·αž“αž”αžΆαž“αž€αŸ†αžŽαžαŸ‹"

αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αž„αŸ’αž€αžΎαžαž”αŸŠαžΌαžαž»αž„αžŠαŸ‚αž›αž αŸ… 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://[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);

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž”αž‰αŸ’αž…αžΌαž›αž”αŸŠαžΌαžαž»αž„αž“αŸαŸ‡ αž’αŸ’αž“αž€αž‚αž½αžšαžαŸ‚αžŸαžΆαž€αž›αŸ’αž”αž„αžœαžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž»αž€αžšαž€αŸ”

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αž™αžΎαž„αž˜αžΆαž“αž€αŸ†αž αž»αžŸαžŠαŸ†αž”αžΌαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αŸ”

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

ហូហូ!

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž…αž»αž…αž›αžΎαž€αŸ†αž αž»αžŸαž”αž‹αž˜αž€αžαžΆ αž’αŸ’αž“αž€αž“αžΉαž„αžƒαžΎαž‰αžŠαžΆαž“αž‡αž„αŸ‹αŸ”

αž€αžΆαžšαžαžΆαž˜αžŠαžΆαž“αž€αŸ†αž αž»αžŸαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αžŠαŸ„αž™αž”αŸ’αžšαžΎ Sentry

αžŸαžΆαžšαž˜αžΎαž›αž‘αŸ…αž’αžΆαž€αŸ’αžšαž€αŸ‹αŸ” αž‡αžΆβ€‹αž€αžΆαžšβ€‹αž–αž·αžβ€‹αžŽαžΆαžŸαŸ‹β€‹αž™αžΎαž„β€‹αž”αžΆαž“β€‹αžƒαžΎαž‰β€‹αžŸαžΆαžšβ€‹αž€αŸ†αž αž»αžŸβ€‹αžŠαŸ„αž™β€‹αž˜αž·αž“β€‹αž™αž›αŸ‹β€‹αž–αžΈβ€‹αž€αž“αŸ’αž›αŸ‚αž„β€‹αžŠαŸ‚αž›β€‹αž€αžΌαžŠβ€‹αž“αŸ„αŸ‡β€‹αŸ” αžαžΆαž˜αž›αŸ†αž“αžΆαŸ†αžŠαžΎαž˜ αž™αžΎαž„αž€αŸ†αž–αž»αž„αž“αž·αž™αžΆαž™αž’αŸ†αž–αžΈαž•αŸ‚αž“αž‘αžΈαž”αŸ’αžšαž—αž–αž“αŸ…αž€αŸ’αž“αž»αž„ ReactJS αž–αŸ’αžšαŸ„αŸ‡αžœαžΆαž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‘αŸαŸ”

αžαŸ’αž‰αž»αŸ†β€‹αž€αŸβ€‹αž…αž„αŸ‹β€‹αž•αŸ’αžαž›αŸ‹β€‹αž€αžΆαžšαžŽαŸ‚αž“αžΆαŸ†β€‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹β€‹αž€αžΆαžšβ€‹αž”αž„αŸ’αž€αžΎαžβ€‹αž•αŸ‚αž“αž‘αžΈβ€‹αž”αŸ’αžšαž—αž– αž”αŸ‰αž»αž“αŸ’αžαŸ‚β€‹αžœαžΆβ€‹αž“αžΉαž„β€‹αž’αŸ’αžœαžΎβ€‹αž±αŸ’αž™β€‹αž’αžαŸ’αžαž”αž‘β€‹αž“αŸαŸ‡β€‹αžœαŸ‚αž„β€‹αž‡αžΆαž„β€‹αž’αŸ’αžœαžΈβ€‹αžŠαŸ‚αž›β€‹αžαŸ’αž‰αž»αŸ†β€‹αž…αž„αŸ‹β€‹αž”αžΆαž“αŸ”

αž’αŸ’αž“αž€αž’αžΆαž…αžŸαž·αž€αŸ’αžŸαžΆαž”αŸ’αžšαž’αžΆαž“αž”αž‘αž“αŸαŸ‡αŸ” αž“αŸ…αž‘αžΈαž“αŸαŸ‡. αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡, αž›αŸ„αž€ Dmitry Nozhenko αž“αžΉαž„αž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αž“αŸ‚αž€αž‘αžΈαž–αžΈαžšαž’αŸ†αž–αžΈαž€αžΆαžšαžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž•αŸ‚αž“αž‘αžΈαž”αŸ’αžšαž—αž–αŸ” αžŠαžΌαž…αŸ’αž“αŸαŸ‡αžŸαžΌαž˜αž…αž»αž… Like αž“αž·αž„ Subscribe αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αž αž›αŸ„αž€ Dmitry NozhenkoαžŠαžΎαž˜αŸ’αž”αžΈαž€αž»αŸ†αž±αŸ’αž™αžαž€αžαžΆαž“αž•αŸ’αž“αŸ‚αž€αž‘αžΈαž–αžΈαžšαŸ”

αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ αž†αŸ’αž˜αžΆαŸ†αŸ” αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž…αŸ†αžŽαž»αž…αž”αž‰αŸ’αž…αž”αŸ‹ αž€αžΆαžš 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": "[email protected]"})
          .setLevel("Error")
      );
      return Sentry.captureException(err);
    }

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

αžαŸ’αž‰αž»αŸ†αž…αž„αŸ‹αž”αŸ’αžšαžΎαž˜αž»αžαž„αžΆαžšαž‘αžΌαž‘αŸ…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ 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);
};

αž“αžΆαŸ†αž…αžΌαž›αž˜αž»αžαž„αžΆαžšαž“αŸαŸ‡αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž αŸ… 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));
      }
    });
};

αžαŸ„αŸ‡αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαŸ–

  • αž€αž˜αŸ’αžšαž·αžαž€αŸ†αžŽαžαŸ‹ αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž”αž‰αŸ’αž…αžΌαž›αž€αŸ†αž αž»αžŸαž€αž˜αŸ’αžšαž·αžαž˜αž½αž™αž‘αŸ…αž€αŸ’αž“αž»αž„αž•αŸ’αž‘αžΆαŸ†αž„αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αž€αžΆαžšαž”αž‰αŸ’αž‡αžΌαž“αŸ” αžœαžΆαž˜αžΆαž“αž›αž€αŸ’αžαžŽαŸˆαžŸαž˜αŸ’αž”αžαŸ’αžαž· - 'fatal', 'error', 'warning', 'log', 'info, 'debug', 'critical') αŸ”
  • αž€αŸ†αžŽαžαŸ‹αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ αž‡αž½αž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αžŽαžΆαž˜αž½αž™ (αž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹ αž’αžΆαžŸαž™αžŠαŸ’αž‹αžΆαž“αž’αŸŠαžΈαž˜αŸ‚αž› αž•αŸ‚αž“αž€αžΆαžšαž‘αžΌαž‘αžΆαžαŸ‹αŸ”αž›αŸ”)αŸ”
  • αž€αŸ†αžŽαžαŸ‹αž”αž“αŸ’αžαŸ‚αž˜ αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŽαžΆαž˜αž½αž™αžŠαŸ‚αž›αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αžΆαžš αž§αž‘αžΆαž αžšαžŽαŸ αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αŸ”

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž…αž„αŸ‹αž‘αž‘αž½αž›αž”αžΆαž“αž˜αžαž·αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž’αŸ†αž–αžΈαž€αŸ†αž αž»αžŸ αž’αŸ’αž“αž€αž‚αž½αžšαžαŸ‚αž”αŸ’αžšαžΎαž˜αž»αžαž„αžΆαžš showReportDialogαŸ”

Sentry.showReportDialog();

αžŸαŸαž…αž€αŸ’αžαžΈαžŸαž“αŸ’αž“αž·αžŠαŸ’αž‹αžΆαž“:

αžαŸ’αž„αŸƒαž“αŸαŸ‡αž™αžΎαž„αž”αžΆαž“αž–αžŽαŸŒαž“αžΆαž’αŸ†αž–αžΈαžœαž·αž’αžΈαž˜αž½αž™αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αž‰αŸ’αž…αžΌαž› Sentry αž‘αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ React αŸ”

β†’ Telegram αž‡αž‡αŸ‚αž€αžŠαŸ„αž™ αž†αŸ’αž˜αžΆαŸ†αŸ”

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹