์ฐ๋ฆฌ๋ React์ ํจ๊ป Sentry๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ชจ์ํ๊ณ ์์ต๋๋ค.
์ด ๊ธฐ์ฌ๋ ๋ค์ ์์ ๋ฅผ ์ฌ์ฉํ์ฌ Sentry ์ค๋ฅ ๋ณด๊ณ ๋ก ์์ํ๋ ์๋ฆฌ์ฆ์ ์ผ๋ถ์
๋๋ค.
๋ฐ์ ๊ตฌํ
๋จผ์ ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ์ 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์ ์ค๋ฅ ๊ธฐ๋ก์ด ์ถ์๋ ๋ฐฐ์น์ ์ค ๋ฒํธ๋ฅผ ์ฐธ์กฐํ๋ค๋ ๊ฒ์ ๋๋ค. ๋ณ๋ก ์ ์ฉํ์ง ์์ต๋๋ค.
Sentry ์๋น์ค๋ ์ค๋ฅ๋ฅผ ์์ ํ ํ ๊ฐ์๋ ํจํท์ ๋ํ ์์ค ๋งต์ ๊ฐ์ ธ์ ์ด๋ฅผ ์ค๋ช ํฉ๋๋ค. ์ด ๊ฒฝ์ฐ์๋ localhost์์ ์คํ ์ค์ ๋๋ค(Sentry ์๋น์ค์์๋ ์ก์ธ์คํ ์ ์์).
์๋ฃจ์ (์์ค ๋งต)
์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ๊ณต์ฉ ์น ์๋ฒ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ ๊ฒ์ ๋๋ค. GitHub ํ์ด์ง ์๋น์ค(๋ฌด๋ฃ)๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๊ฐ๋จํ ์๋ต ๋ฒํผ XNUMX๊ฐ. ์ฌ์ฉ ๋จ๊ณ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
-
ํด๋์ ๋ด์ฉ์ ๋ณต์ฌํ์ธ์. ๋น๋ ํด๋๋ก ๋ฌธ์ ์ ์ฅ์์ ๋ฃจํธ ๋๋ ํฐ๋ฆฌ์ ์์ต๋๋ค.
-
์ผ๋ค GitHub ํ์ด์ง ์ ์ฅ์(GitHub์)์์ docs ํด๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์์ฌ ๊ฐ์ง
-
GitHub์ ๋ณ๊ฒฝ ์ฌํญ ํธ์
์ฃผ์: ๋ฌด์์ ์ฌ์ฉํด์ผ ํ๋์ง ํ์ ํ ํ ์์ฑ-์์ฑ-์ฑ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ ํ ํ์ด์ง ๊ธฐ๋ฅ. package.json์ ๋ค์์ ์ถ๊ฐํ์ต๋๋ค.
"homepage": "https://larkintuckerllc.github.io/hello-sentry/"
์คํ ์ค์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ต์ข ๋ฒ์ ์ ๋ค์ ์์น์์ ๊ตฌํ ์ ์์ต๋๋ค.
์กํ ๋ฒ๋ ์ ๊ทธ๋ฆผ
Hello ๋ฒํผ์ ํด๋ฆญํ๋ ๊ณผ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ํ์๋ฉ๋๋ค.
๊ด์ฐฐ :
- ์ด ๋ฒ๊ทธ ๋ณด๊ณ ์๋ ์ด๋ณด๋ค ๋ ๋ช ํํ ์ ์์ต๋๋ค. ๋ธ๋ผ๋ณด.
์ค๋ช ๋์ง ์์ ์ค๋ฅ์ ๋ํ ์์
๋ง์ฐฌ๊ฐ์ง๋ก ๋ฒํผ ํด๋ฆญ์ ๋ํด์๋ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ค๋ฅ.
๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ํ์๋ฉ๋๋ค.
์ค๋ช ๋์ง ์์ ์ค๋ฅ ์ฒ๋ฆฌ ๊ฐ์ (๋ ๋๋ง)
์ค๋ฅ ํ๊ณ ์๊ฐ
์ฌ์ฉ์ ์ธํฐํ์ด์ค ์ผ๋ถ์ 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์ ์ค๋ฅ๊ฐ ๋ณด๊ณ ๋ฉ๋๋ค.
์์ฑ
์ด ์ ๋ณด๊ฐ ๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
Sentry๋ฅผ ํตํ PS Telegram ์ฑํ
์ถ์ฒ : habr.com