Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

์˜ค๋Š˜์€ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‹ค์‹œ๊ฐ„ ์˜ค๋ฅ˜ ์ถ”์ ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ”„๋ŸฐํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์˜ค๋ฅ˜ ์ถ”์ ์— ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ํšŒ์‚ฌ์—์„œ๋Š” ์ข…์ข… ๋ฒ„๊ทธ ์ถ”์ ์„ ๋ฏธ๋ฃจ๊ณ  ๋ฌธ์„œํ™”, ํ…Œ์ŠคํŠธ ๋“ฑ์„ ๋งˆ์นœ ํ›„์— ๋ฒ„๊ทธ ์ถ”์ ์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ œํ’ˆ์„ ๋” ๋‚˜์€ ๋ฐฉํ–ฅ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜์‹ญ์‹œ์˜ค!

1. ์„ผํŠธ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹น์‹ ์ด ์ƒ์‚ฐ ๊ณผ์ •์—์„œ ๋ฒ„๊ทธ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

์ข‹์•„์š”, ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ Sentry๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ์š” ์ด์œ :

  • ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋ฐฐํฌํ•  ๋•Œ ์œ„ํ—˜์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ํ…Œ์ŠคํŠธ๋กœ QA ์ง€์›
  • ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋น ๋ฅธ ์•Œ๋ฆผ ๋ฐ›๊ธฐ
  • ์˜ค๋ฅ˜๋ฅผ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ •ํ•˜๋Š” ๋Šฅ๋ ฅ
  • ๊ด€๋ฆฌ์ž ํŒจ๋„์—์„œ ์˜ค๋ฅ˜๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ‘œ์‹œํ•˜๊ธฐ
  • ์‚ฌ์šฉ์ž/๋ธŒ๋ผ์šฐ์ € ์„ธ๊ทธ๋จผํŠธ๋ณ„๋กœ ์˜ค๋ฅ˜ ์ •๋ ฌ

CEO/๋ฆฌ๋“œ ํ”„๋กœ์ ํŠธ์˜ ์ฃผ์š” ์ด์œ 

  • ๋น„์šฉ ์ ˆ๊ฐ(Sentry๋Š” ์„œ๋ฒ„์— ์„ค์น˜ ๊ฐ€๋Šฅ)
  • ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ ๋ฐ›๊ธฐ
  • ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ”„๋กœ์ ํŠธ์˜ ๋ฌธ์ œ์  ํŒŒ์•…
  • ์‚ฌ๋žŒ๋“ค์ด ์•ฑ๊ณผ ๊ด€๋ จํ•ด ๊ฒช๊ณ  ์žˆ๋Š” ๋ฌธ์ œ์˜ ์ˆ˜๋ฅผ ์ดํ•ดํ•˜์„ธ์š”.
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ค์ˆ˜ํ•œ ๋ถ€๋ถ„์„ ์ฐพ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๋“ค์ด ์ด ๊ธ€์— ๋จผ์ € ๊ด€์‹ฌ์„ ๊ฐ€์งˆ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ์ด์œ  ๋ชฉ๋ก์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์‚ฌ๊ฐ€ Sentry๋ฅผ ํ†ตํ•ฉํ•˜๋„๋ก ์„ค๋“ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์—…์ฒด ๋ชฉ๋ก์˜ ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์— ์ฃผ์˜ํ•˜์„ธ์š”.

์ด๋ฏธ ๊ด€์‹ฌ์ด ์žˆ์œผ์‹ ๊ฐ€์š”?

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

์„ผํŠธ๋ฆฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

Sentry๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถฉ๋Œ์„ ์ถ”์ ํ•˜๊ณ  ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ๋ฒ„๊ทธ ์ถ”์  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž…๋‹ˆ๋‹ค. ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํšจ์œจ์„ฑ์„ ๋†’์ด๊ณ  ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. Sentry๋Š” JavaScript, Node, Python, PHP, Ruby, Java ๋ฐ ๊ธฐํƒ€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

2. ๋กœ๊ทธ์ธ ํ›„ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

  • Sentry ๊ณ„์ •์„ ๊ฐœ์„คํ•˜์„ธ์š”. ๋กœ๊ทธ์ธํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. (Sentry๋Š” ์„œ๋ฒ„์— ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
  • ๋‹ค์Œ ๋‹จ๊ณ„๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๋ชฉ๋ก์—์„œ ์–ธ์–ด๋ฅผ ์„ ํƒํ•˜์„ธ์š”. (์šฐ๋ฆฌ๋Š” React๋ฅผ ์„ ํƒํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. "Create Project"๋ฅผ ํด๋ฆญํ•˜์„ธ์š”)

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งž์ถค์„ค์ •ํ•˜์„ธ์š”. 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. React์™€ Sentry ํ†ตํ•ฉ

ํ”„๋กœ์ ํŠธ์— npm ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

npm i @sentry/browser

์ปจํ…Œ์ด๋„ˆ์—์„œ Sentry๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

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

DSN์€ ํ”„๋กœ์ ํŠธ -> ์„ค์ • -> ํด๋ผ์ด์–ธํŠธ ํ‚ค์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰์ฐฝ์—์„œ ํด๋ผ์ด์–ธํŠธ ํ‚ค๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

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

4. ์ฒซ ๋ฒˆ์งธ ์˜ค๋ฅ˜ ์ถ”์ 

์˜ˆ๋ฅผ ๋“ค์–ด Deezer API์™€ ํ•จ๊ป˜ ๊ฐ„๋‹จํ•œ ์Œ์•… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์—ฌ๊ธฐ์—. ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ "์ •์˜๋˜์ง€ ์•Š์€" ์†์„ฑ์— ์•ก์„ธ์Šคํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ˜ธ์ถœํ•˜๋Š” ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. console.log ั ์‚ฌ์šฉ์ž.์ด๋ฉ”์ผ. ์ด ์ž‘์—… ํ›„์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์žกํžˆ์ง€ ์•Š์€ TypeError(์ •์˜๋˜์ง€ ์•Š์€ ์†์„ฑ์„ ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค) email) ์‚ฌ์šฉ์ž ๊ฐœ์ฒด๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋˜ํ•œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์™ธ.

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

์ด ๋ฒ„ํŠผ์„ ํ†ตํ•ฉํ•œ ํ›„ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

์ฒซ ๋ฒˆ์งธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

์šฐํ›„!

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

ํ—ค๋” ์˜ค๋ฅ˜๋ฅผ ํด๋ฆญํ•˜๋ฉด ์Šคํƒ ์ถ”์ ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

Sentry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜ค๋ฅ˜ ์ถ”์ 

๋ฉ”์‹œ์ง€๊ฐ€ ์ข‹์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์šฐ๋ฆฌ๋Š” ์ฝ”๋“œ๊ฐ€ ์–ด๋””์— ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ฑ„ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ReactJS์˜ ์†Œ์Šค ๋งต์€ ๊ตฌ์„ฑ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์†Œ์Šค ๋งต ์„ค์ •์— ๋Œ€ํ•œ ์ง€์นจ๋„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์ด ๊ธ€์ด ์˜๋„ํ•œ ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๊ธธ์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์ฃผ์ œ๋ฅผ ๊ณต๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์—ฌ๊ธฐ์—. ์ด ๊ธฐ์‚ฌ์— ๊ด€์‹ฌ์ด ์žˆ์œผ์‹œ๋ฉด, ๋“œ๋ฏธํŠธ๋ฆฌ ๋…ธ์  ์ฝ” ์†Œ์Šค ๋งต ํ†ตํ•ฉ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์„ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ข‹์•„์š”์™€ ๊ตฌ๋…์„ ๋” ๋งŽ์ด ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š” ๋“œ๋ฏธํŠธ๋ฆฌ ๋…ธ์  ์ฝ”๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์„ ๋†“์น˜์ง€ ์•Š๋„๋ก.

5. ์‚ฌ์šฉ ๋ณด์ดˆ ๋์  ์žˆ์Œ API

์ข‹์•„์š”. ์šฐ๋ฆฌ๋Š” ์ด์ „ ๋‹จ๋ฝ์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์™ธ๋ฅผ ๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 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));
    }
  });

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

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

๋ฐฉ๋ฒ•์„ ํ™•์ธํ•ด ๋ด…์‹œ๋‹ค:

  • ์„ธํŠธ๋ ˆ๋ฒจ ์„ผํŠธ๋ฆฌ ๋Œ€์‹œ๋ณด๋“œ์— ๋ ˆ๋ฒจ ์˜ค๋ฅ˜๋ฅผ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” '์น˜๋ช…์ ', '์˜ค๋ฅ˜', '๊ฒฝ๊ณ ', '๋กœ๊ทธ', '์ •๋ณด, '๋””๋ฒ„๊ทธ', '์ค‘์š”') ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ์„ค์ • ๋ชจ๋“  ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ(ID, ์ด๋ฉ”์ผ ์ฃผ์†Œ, ๊ฒฐ์ œ ๊ณ„ํš ๋“ฑ)๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
  • ์„ธํŠธ์—‘์ŠคํŠธ๋ผ ์˜ˆ๋ฅผ ๋“ค์–ด ์ €์žฅ๊ณผ ๊ฐ™์ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ์„ ์–ป์œผ๋ ค๋ฉด showReportDialog ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Sentry.showReportDialog();

๊ฒฐ๋ก  :

์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” Sentry๋ฅผ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ†ตํ•ฉํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

โ†’ ํ…”๋ ˆ๊ทธ๋žจ ์ฑ„ํŒ… ๋ณด์ดˆ

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€