React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

์šฐ๋ฆฌ๋Š” React์™€ ํ•จ๊ป˜ Sentry๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ์ƒ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

์ด ๊ธฐ์‚ฌ๋Š” ๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Sentry ์˜ค๋ฅ˜ ๋ณด๊ณ ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์‹œ๋ฆฌ์ฆˆ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ะงะฐัั‚ัŒ 1.

๋ฐ˜์‘ ๊ตฌํ˜„

๋จผ์ € ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์ƒˆ Sentry ํ”„๋กœ์ ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์„ผํŠธ๋ฆฌ ํ™ˆํŽ˜์ด์ง€์—์„œ ์ด ๊ฒฝ์šฐ React๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

React๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Hello์™€ Error๋ผ๋Š” ๋‘ ๊ฐœ์˜ ๋ฒ„ํŠผ์„ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์‹œ์ž‘ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

npx create-react-app react-app

๊ทธ๋Ÿฐ ๋‹ค์Œ Sentry ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

yarn add @sentry/browser

์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ ์•ฑ/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,
  });
}
...

๊ด€์ฐฐ :

  • ๊ฐœ๋ฐœ ์ค‘์—๋Š” ์ฝ˜์†”๊ณผ ๊ฐ™์ด ๋ฌธ์ œ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค๋ฅธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ์œผ๋ฏ€๋กœ ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋งŒ Sentry๋ฅผ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ Hello ๋ฐ Error ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ด๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ ์•ฑ/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);
    }
  }
}

๋ฐ˜์‘ ์•ฑ/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');
  }
}

๋ฐ˜์‘ ์•ฑ/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;

๋ฌธ์ œ(์†Œ์Šค ๋งต)

๋‹ค์Œ์„ ์ž…๋ ฅํ•˜์—ฌ ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ๋กœ Sentry๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

yarn build

๋นŒ๋“œ ํด๋”์—์„œ ๋‹ค์Œ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

npx http-server -c-1

์šฐ๋ฆฌ๊ฐ€ ์ฆ‰์‹œ ์ง๋ฉดํ•˜๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ๋Š” Sentry์˜ ์˜ค๋ฅ˜ ๊ธฐ๋ก์ด ์ถ•์†Œ๋œ ๋ฐฐ์น˜์˜ ์ค„ ๋ฒˆํ˜ธ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ„๋กœ ์œ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

Sentry ์„œ๋น„์Šค๋Š” ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์‹ ํ•œ ํ›„ ๊ฐ์†Œ๋œ ํŒจํ‚ท์— ๋Œ€ํ•œ ์†Œ์Šค ๋งต์„ ๊ฐ€์ ธ์™€ ์ด๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” localhost์—์„œ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค(Sentry ์„œ๋น„์Šค์—์„œ๋Š” ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Œ).

์†”๋ฃจ์…˜(์†Œ์Šค ๋งต)

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์€ ๊ณต์šฉ ์›น ์„œ๋ฒ„์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. GitHub ํŽ˜์ด์ง€ ์„œ๋น„์Šค(๋ฌด๋ฃŒ)๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ ์‘๋‹ต ๋ฒ„ํŠผ XNUMX๊ฐœ. ์‚ฌ์šฉ ๋‹จ๊ณ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ํด๋”์˜ ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•˜์„ธ์š”. ๋นŒ๋“œ ํด๋”๋กœ ๋ฌธ์„œ ์ €์žฅ์†Œ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์žˆ์Šต๋‹ˆ๋‹ค.

  2. ์ผœ๋‹ค GitHub ํŽ˜์ด์ง€ ์ €์žฅ์†Œ(GitHub์˜)์—์„œ docs ํด๋”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„์‚ฌ ๊ฐ€์ง€

  3. GitHub์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ ํ‘ธ์‹œ

์ฃผ์˜: ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ํŒŒ์•…ํ•œ ํ›„ ์ƒ์„ฑ-์ƒ์„ฑ-์•ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ํ™ˆ ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ. package.json์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

์‹คํ–‰ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ตœ์ข… ๋ฒ„์ „์€ ๋‹ค์Œ ์œ„์น˜์—์„œ ๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์žกํžŒ ๋ฒŒ๋ ˆ์˜ ๊ทธ๋ฆผ

Hello ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋Š” ๊ณผ์ •์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

๊ด€์ฐฐ :

  • ์ด ๋ฒ„๊ทธ ๋ณด๊ณ ์„œ๋Š” ์ด๋ณด๋‹ค ๋” ๋ช…ํ™•ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ๋ณด.

์„ค๋ช…๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์˜ˆ์‹œ

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฒ„ํŠผ ํด๋ฆญ์— ๋Œ€ํ•ด์„œ๋„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฅ˜.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

์„ค๋ช…๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๊ฐœ์„ (๋ Œ๋”๋ง)

์˜ค๋ฅ˜ ํ•œ๊ณ„ ์†Œ๊ฐœ

์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์ผ๋ถ€์˜ JavaScript ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ค‘๋‹จ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. React ์‚ฌ์šฉ์ž์˜ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด React 16์—์„œ๋Š” "์˜ค๋ฅ˜ ๋ฒ”์œ„"๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

...

๊ฐ์ง€๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ๋™์ž‘

์ด ๋ณ€ํ™”๋Š” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. React 16๋ถ€ํ„ฐ ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„์— ์˜ํ•ด ํฌ์ฐฉ๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ „์ฒด React ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๊ฐ€ ๋งˆ์šดํŠธ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.

- ๋Œ„ ์•„๋ธŒ๋ผ๋ชจํ”„ - React 16์˜ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ๊นจ๋‹ซ๊ธฐ๊นŒ์ง€ ์‹œ๊ฐ„์ด ์ข€ ๊ฑธ๋ ธ๋˜ ์ค‘์š”ํ•œ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์œ„์˜ ๋™์ž‘์€ ๋ Œ๋”๋ง ๋ฉ”์„œ๋“œ(๋˜๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ๋†’์Œ)์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์—์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.. ์˜ˆ๋ฅผ ๋“ค์–ด ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ„ํŠผ์— ์•„๋ฌด ์†Œ์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ์˜ค๋ฅ˜; ์ด ์˜ค๋ฅ˜๋Š” ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ์— ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ ๋ Œ๋”๋ง ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“  ๋‹ค์Œ ์˜ค๋ฅ˜ ๋ฒ”์œ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋ฅ˜๋ฅผ ๋ณด๋‹ค ์ ์ ˆํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ ์•ฑ/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,
    });
  }
}

๊ด€์ฐฐ :

  • ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ๋ฐ˜์‘ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค ๊นƒ๋ฐœ.ํŒŒ๊ดด.๊ฐ€์งœ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„๊ฐ€ ์—†์œผ๋ฉด ์ „์ฒด ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๊ฐ€ ๋งˆ์šดํŠธ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์˜ค๋ฅ˜ ๊ฒฝ๊ณ„ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค(์ƒˆ๋กœ์šด ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ). ์ปดํฌ๋„ŒํŠธDidCatch); ์ด๊ฒƒ์€ ๋ณธ์งˆ์ ์œผ๋กœ Dan Abramov์˜ ๊ธฐ์‚ฌ์— ์ œ๊ณต๋œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

๋ฐ˜์‘ ์•ฑ/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;
  }
}

๋งˆ์ง€๋ง‰์œผ๋กœ ๋‹ค์Œ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ ์•ฑ/src/App.js

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

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

๊ทธ๋Ÿฌ๋‚˜ Render Error ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด fallback UI๊ฐ€ ํ‘œ์‹œ๋˜๊ณ  Sentry์— ์˜ค๋ฅ˜๊ฐ€ ๋ณด๊ณ ๋ฉ๋‹ˆ๋‹ค.

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

React ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„๊ทธ์— ๋Œ€ํ•œ Sentry ์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง

์™„์„ฑ

์ด ์ •๋ณด๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

PS ์›๋ณธ ๋งํฌ

Sentry๋ฅผ ํ†ตํ•œ PS Telegram ์ฑ„ํŒ… https://t.me/sentry_ru

์ถœ์ฒ˜ : habr.com

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