# 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('센트리 에러 테스트')`*** ![](https://i.imgur.com/JkenNWy.jpg) 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를 발급 & 복사해주세요 ![](https://i.imgur.com/iBeU6pt.png) 8. 신영님께 배포 스크립트 수정을 요청하며 다음과 같이 전달합니다. 환경변수 하나만 설정해달라고 요청(`SENTRY_AUTH_TOKEN`에다가 방금 복사해둔 Auth Tokens를 넣어달라 요청) + .js.map으로 끝나는 빌드 결과물은 배포하면 안됩니다. 또는 테스트중이라면 빌드 스크립트에서 넣어주면 됩니다. 9. 이제 npm run build시에 빌드 결과물이 떨어지면서 동시에 sentry에 sourcemap이 업로드 됩니다. 10. 일부러 에러를 내보고 테스트 및 production에 적용!