Skip to content

Commit

Permalink
Feat: Hotjar, Sentry 설치 및 초기 설정 (#206)
Browse files Browse the repository at this point in the history
* refactor: constant 파일 정리 몇몇 파일 common에 통합

* feat: hotjar 설치 및 초기 설정

* feat: Sentry 초기 설정

* feat: Errorboundary Error를 Sentry로 전달

* refactor: GA와 Hotjar 초기화  Sentry와 분리

* refactor: 에러 메시지 포멧 변경, sentry 환경변수 설정

* refactor: fallback이 제공된 경우 핸들링된 오류로 캡처
  • Loading branch information
dev-dong-su authored May 12, 2024
1 parent fceee66 commit 37eee48
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 36 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
"build-storybook": "storybook build"
},
"dependencies": {
"@sentry/react": "^7.114.0",
"@storybook/addon-styling-webpack": "^0.0.5",
"@storybook/addon-themes": "^7.6.6",
"@tanstack/react-query": "^5.24.7",
"@tanstack/react-query-devtools": "^5.24.7",
"@testing-library/dom": "^9.3.1",
"@types/styled-components": "^5.1.26",
"@vercel/analytics": "^1.1.1",
"axios": "^1.4.0",
"chart.js": "^4.4.1",
"chartjs-plugin-datalabels": "^2.2.0",
Expand All @@ -39,6 +39,7 @@
"react-helmet-async": "^1.3.0",
"react-hooks-testing-library": "^0.6.0",
"react-hot-toast": "^2.4.1",
"react-hotjar": "^6.3.1",
"react-i18next": "^13.5.0",
"react-router-dom": "^6.11.2",
"recoil": "^0.7.7",
Expand Down
144 changes: 122 additions & 22 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { lazy, Suspense, useEffect } from 'react';
import { Route, Routes } from 'react-router-dom';

import { inject } from '@vercel/analytics';
import { useResetRecoilState } from 'recoil';

import ErrorBoundary from '@components/base/ErrorBoundary';
Expand All @@ -16,8 +15,6 @@ import { LOCAL_STORAGE_KEY } from '@constants/localStorage.constant';
import PATH from '@constants/path.constant';
import useLocalStorage from '@hooks/useLocalStorage';

inject();

const MainPage = lazy(() => import('@pages/main/MainPage'));

const SnackGamePage = lazy(
Expand Down
2 changes: 1 addition & 1 deletion src/components/Level/Level.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TIER_COLOR } from '@constants/tier.constant';
import { TIER_COLOR } from '@constants/common.constant';

interface LevelProps {
level: number;
Expand Down
15 changes: 15 additions & 0 deletions src/components/base/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Component, ComponentType, PropsWithChildren } from 'react';

import * as Sentry from '@sentry/react';

export interface FallbackProps {
error?: Error;
resetErrorBoundary?: () => void;
Expand Down Expand Up @@ -37,6 +39,19 @@ class ErrorBoundary extends Component<
return { error };
}

componentDidCatch(error: Error): void {
Sentry.withScope((scope) => {
scope.setLevel('error');
Sentry.captureMessage(
`[🚨 ${import.meta.env.VITE_NODE_ENV}에러 ${error.name}]: ${window.location.href}`,
);

Sentry.captureException(error, {
mechanism: { handled: !!this.props.fallback },
});
});
}

render() {
const { fallback: FallbackComponent } = this.props;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const TOAST_ID = 'toast';

export const PRIMARY_COLOR = 'rgba(255, 237, 213, 1)';

export const TIER_COLOR = [
Expand All @@ -10,3 +12,6 @@ export const TIER_COLOR = [
'rgba(223, 164, 225, 1)',
'rgba(239, 191, 191, 1)',
];

export const HJID = 4963723;
export const HJSV = 6;
1 change: 0 additions & 1 deletion src/constants/toast.constant.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/hooks/useToast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSetRecoilState } from 'recoil';
import { toastState } from '@utils/atoms/common.atom';
import { ToastType } from '@utils/types/common.type';

import { TOAST_ID } from '@constants/toast.constant';
import { TOAST_ID } from '@constants/common.constant';

const useToast = () => {
const setToastState = useSetRecoilState(toastState);
Expand Down
32 changes: 29 additions & 3 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React, { useEffect } from 'react';
import { useEffect } from 'react';
import { createRoot } from 'react-dom/client';
import ReactGA from 'react-ga4';
import { HelmetProvider } from 'react-helmet-async';
import { hotjar } from 'react-hotjar';
import { BrowserRouter } from 'react-router-dom';

import * as Sentry from '@sentry/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RecoilRoot } from 'recoil';

import { HJID, HJSV } from '@constants/common.constant';

import App from './App';

const queryClient = new QueryClient({
Expand All @@ -25,8 +29,30 @@ const queryClient = new QueryClient({

const Root = () => {
useEffect(() => {
if (!import.meta.env.VITE_GA_TRACKING_ID) return;
ReactGA.initialize(import.meta.env.VITE_GA_TRACKING_ID);
if (import.meta.env.VITE_NODE_ENV === 'production') {
ReactGA.initialize(import.meta.env.VITE_GA_TRACKING_ID);

hotjar.initialize({ id: HJID, sv: HJSV });
}

if (import.meta.env.VITE_NODE_ENV !== 'development') {
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DNS,
environment: import.meta.env.VITE_NODE_ENV,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration(),
],

// Performance Monitoring
tracesSampleRate: 1.0,
tracePropagationTargets: ['localhost', /^https:\/\/api.snackga.me/],

// Session Replay
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
}
}, []);

ReactGA.send({
Expand Down
2 changes: 1 addition & 1 deletion src/pages/games/SnackGame/game/components/ExpBarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ChartDataLabels from 'chartjs-plugin-datalabels';

import { StatusType } from '@utils/types/member.type';

import { TIER_COLOR } from '@constants/tier.constant';
import { TIER_COLOR } from '@constants/common.constant';

import type { ChartOptions, Plugin } from 'chart.js';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const SnackGameView = ({ isOngoing, snackGame, onRemove }: SnackGameProps) => {
return (
<div
ref={canvasBaseRef}
className={'max-w-xl mx-auto mb-20 h-[75%] w-full'}
className={'mx-auto mb-20 h-[75%] w-full max-w-xl'}
>
{isOngoing && (
<canvas
Expand Down
2 changes: 1 addition & 1 deletion src/pages/user/components/ExpChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Chart as ChartJS, ArcElement, ChartOptions } from 'chart.js';

import { StatusType } from '@utils/types/member.type';

import { TIER_COLOR, PRIMARY_COLOR } from '@constants/tier.constant';
import { PRIMARY_COLOR, TIER_COLOR } from '@constants/common.constant';

ChartJS.register(ArcElement);

Expand Down
2 changes: 1 addition & 1 deletion src/utils/atoms/common.atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { atom, selector } from 'recoil';
import { ModalType, toastStateType } from '@utils/types/common.type';

import { ATOM_KEY } from '@constants/atom.constant';
import { TOAST_ID } from '@constants/toast.constant';
import { TOAST_ID } from '@constants/common.constant';

export const modalState = atom<ModalType>({
key: ATOM_KEY.MODAL,
Expand Down

0 comments on commit 37eee48

Please sign in to comment.