# Sentry
### Why Sentry?
- **에러 탐지**에 특화되어있음
- 프리티어만 사용하더라도 어떤 에러가 어느 코드에서 발생하는지 추적 가능(sourcemap upload 필요)
- 하지만 성능개선을 위한 지표도 제공
- 성능개선은 개발자가 다양한 기법을 적용하며 유도할 수 있음
- Throttle
- 수행할 콜백을 덮어씌울것인가 말것인가(Origin)
```typescript
const getThrottle = () => {
let waiting = false;
let willExecuteCallback: () => void;
return (callback: () => void, time: number) => {
willExecuteCallback = () => callback();
if (!waiting) {
waiting = true;
setTimeout(() => {
willExecuteCallback();
waiting = false;
}, time);
}
};
};
const getOriginThrottle = () => {
let waiting = false;
return (callback: () => void, time: number) => {
if (!waiting) {
waiting = true;
setTimeout(() => {
callback();
waiting = false;
}, time);
}
};
};
```
- Debounce
```typescript
const getDebounce = () => {
let timeoutId: NodeJS.Timeout | undefined = undefined;
return (callback: () => void, time: number) => {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(callback, time);
};
};
```
- setTimeout/setInterval => [requestAnimationFrame](https://developer.mozilla.org/ko/docs/Web/API/window/requestAnimationFrame)
- 무한스크롤에도 적용 할 수 있어요 ㅎㅎ
- https://tech.kakaoenterprise.com/149
- etc...
### 적용 방법
***아래를 적용하기 전에 우선적으로 도커에 띄워서 테스트해보아야 한다는 점을 참고해주세요. 에러를 일부러 내보고 다음처럼 Issues 탭에 항목이 떠야합니다. `throw new Error('센트리 에러 테스트')`***

1. [Sentry 홈페이지](https://sentry.io/welcome/)에서 회사 계정으로 회원가입
2. 로그인 후 sentry 홈페이지에 접속하면 Organization 만들라는 페이지로 이동하게 될텐데 적절한 name(lighthouse or todaycare)을 적은 후 create합니다.
3. [새 Project 만들기](https://docs.sentry.io/product/sentry-basics/integrate-frontend/create-new-project/) 링크에서 Step1만 따라해주세요. [리액트 설정](https://docs.sentry.io/platforms/javascript/guides/react/) 링크에서 Configure 참고하시면 되며 코드를 보시면 `dsn: "(화살표 아래방향)https://123!#@!#!@#"` 이런식으로 나올 텐데 클릭하셔서 자신이 만든 프로젝트를 선택해주시고 해당 DSN은 복사해두세요. 위 링크에서 설치하라는 패키지 외에 아래 패키지를 추가적으로 설치합니다.
```bash
npm install @sentry/integrations
npm install -D @sentry/webpack-plugin
```
최종적으로 아래와 같은 코드를 설정해주시면 되어요
```typescript
// index.tsx or App.tsx
// redux 설정 코드가 들어가는 그 파일입니다
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';
import { Offline as OfflineIntegration } from '@sentry/integrations';
// OfflineIntegration은 사용자가 Offline일 때 에러가 발생하면
// 브라우저의 IndexDB에 저장해두었다가
// 온라인이 되었을 때 쏴주는 아이입니다
if (process.env.NODE_ENV === 'production') {
Sentry.init({
dsn: process.env.SENTRY_DSN,
integrations: [new BrowserTracing(), new OfflineIntegration({ maxStoredEvents: 60 })],
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV,
release: 'head',
});
}
```
4. 웹팩도 설정해야합니다. production webpack만 설정해주세요
```javascript
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
module.exports = {
...,
devtool: 'source-map',
// 여기서 나온 sourcemap은 Sentry에 업로드 하며
// 배포되어서는 아니되는 파일입니다
...,
plugins: [
new SentryWebpackPlugin({
authToken: process.env.SENTRY_AUTH_TOKEN,
org: 'lighthouse-km', // organization 이름
ignore: ['node_modules', 'webpack.dev.js', 'webpack.prod.js'],
project: 'carehouse-production', // 프로젝트명
include: './build', // 빌드폴더 명
release: 'head',
urlPrefix: '~/', // 배포되었을 때 static file(배포 결과물)들이 위치하는 url prefix
}),
]
}
```
5. ErrorBoundary가 Router를 감싸주어야 합니다. 하단 코드를 참고해주세요
```typescript
// SentryErrorBoundary.tsx
import { ErrorBoundary } from '@sentry/react';
import ErrorBoundaryFallback from '~/pages/ErrorBoundaryFallback';
interface Props {
children: React.ReactNode;
}
export default function SentryErrorBoundary({ children }: Props) {
return (
<ErrorBoundary fallback={({ resetError }) => <ErrorBoundaryFallback resetError={resetError} />}>{children}</ErrorBoundary>
);
}
```
```typescript
// ErrorBoundaryFallback.tsx
interface Props {
resetError: () => void;
}
const ErrorBoundaryFallback: React.FC<Props> = ({ resetError }) => {
const globalState = useSelector((state: RootState) => state.globalReducer);
return (
<S.Container>
<Logo
to={globalState[KEY.GLOBAL.USER.TYPE] === UserType.INSTITUTE ? PATH.INSTITUTE_HOME : PATH.GUARDIAN_HOME}
business={globalState[KEY.GLOBAL.USER.TYPE] === UserType.INSTITUTE}
onClick={() => resetError()}
/>
<br />
<S.Description>
오류가 발생하였습니다.
<br />
불편을 드려 죄송합니다.
<br />
해당 화면이 반복될 경우
<br />
오른쪽 하단 채널톡으로 문의주시기 바랍니다.
</S.Description>
<br />
<Button
width={200}
height={48}
color={'primary'}
borderradius={6}
btnLinkinize
to={globalState[KEY.GLOBAL.USER.TYPE] === UserType.INSTITUTE ? PATH.INSTITUTE_HOME : PATH.GUARDIAN_HOME}
onClick={() => resetError()}>
홈으로 이동
</Button>
</S.Container>
);
};
export default ErrorBoundaryFallback;
```
```typescript
// router.tsx
<Router>
<Switch>
<SentryErrorBoundary>
// ...
<Route path={PATH.GUARDIAN_HOME} exact component={GuardianHomePage} />
// ...
</SentryErrorBoundary>
</Switch>
</Router>
```
6. 아까 복사해둔 DSN 주소는 env파일에 SENTRY_DSN으로 넣어두시구요
7. 다음 위치에서 Auth Tokens를 발급 & 복사해주세요

8. 신영님께 배포 스크립트 수정을 요청하며 다음과 같이 전달합니다. 환경변수 하나만 설정해달라고 요청(`SENTRY_AUTH_TOKEN`에다가 방금 복사해둔 Auth Tokens를 넣어달라 요청) + .js.map으로 끝나는 빌드 결과물은 배포하면 안됩니다. 또는 테스트중이라면 빌드 스크립트에서 넣어주면 됩니다.
9. 이제 npm run build시에 빌드 결과물이 떨어지면서 동시에 sentry에 sourcemap이 업로드 됩니다.
10. 일부러 에러를 내보고 테스트 및 production에 적용!