Skip to content

[Settings] Frontend 에러 모니터링 툴 Sentry를 도입한다.#349

Merged
JuJangGwon merged 16 commits intodevfrom
settings/#310-sentry
Feb 4, 2026
Merged

[Settings] Frontend 에러 모니터링 툴 Sentry를 도입한다.#349
JuJangGwon merged 16 commits intodevfrom
settings/#310-sentry

Conversation

@JuJangGwon
Copy link
Copy Markdown
Collaborator

🔗 관련 이슈

Closes #310

✅ 작업 내용

프로젝트에 Sentry 모니터링을 도입하기 위한 기본 인프라를 구축했습니다
에러 등급에 따라 Error레벨, Warning레벨을 부여하여 전송하도록 했으며, 기준은 채팅과 스킵처럼 핵심 기능은 아니지만 사용자 경험에 영향을 주는 것은 warning 레벨로, 입장/제출/투표처럼 배틀 진행에 필수적인 것은 error 레벨로 분류했습니다.

1. 사용자 컨텍스트 추적

배틀 중 에러가 발생했을 때 누가 겪은 문제인지를 바로 알 수 있도록 사용자 정보를 Sentry에 연동했습니다.
유저가 게스트 로그인 또는 OAuth 로그인 한다면 클라이언트 메모리에 사용자 ID, 닉네임, 로그인 타입을 저장하고, 오류가 발생되어 센트리 로그 전송됐을 시, 에러 발생자 정보도 같이 보고 받게 됩니다.

 Sentry.setUser({
    id: oauthUser.id,
    username: oauthUser.nickname,
    provider: oauthUser.provider,
    type: 'oauth'
  });

왜 넣었는가?

게스트 사용자의 문제인지, OAuth 사용자의 문제인지, 특정 사용자에게만 반복적으로 발생하는 문제인지 파악하기 위함.

2. ErrorBoundary에 Sentry 구독

저희 프로젝트에서 에러 발생시 핸들링 방식은 아래와 같습니다

  • 앱 최상단에서는React-router ErrorBoundary 가 리액트 컴포넌트 트리에서 발생하는 예상치 못한 에러나, 미처 핸들링하지 못한 api 에러들을 캐치 하면 에러 페이지로 라우팅
  • 특정 컴포넌트에 에러가 발생할 때 마다 SectionErrorBoundary가 캐치한 후 해당 영역만 Fallback 컴포넌트를 렌더링
  • 눈에 보이지 않는 상태들을 바꾸는 api가 실패 한 경우를 catch해서 Error Toast 띄우기

각각의 상황 때마다 일관적으로 처리해주는 공용 컴포넌트들을 이용하게 되는데 React-router의 errorElement나 SectionErrorBoundary에서 에러를 캐치하게 된다면 Sentry에 에러 로그를 자동으로 전송하도록 했습니다.

아참 Toast의 경우는 일일이... 기입했어요.. 알림 용도로 사용될 때가 있어서... 나중에 리펙토링 할 때 type을 나눠서 errorType Toast의 경우 자동으로 센트리에 로깅하게 하면 괜 찮을지도..?(또는 prop)

기대 효과

에러 발생 시 어떤 컴포넌트에서 발생했는지, 컴포넌트 스택은 어떻게 되는지, 현재 URL은 무엇인지 같은 컨텍스트 정보를 함께 전송합니다. Session Replay와 에러 샘플링 비율도 설정했습니다.


3. 소켓 에러 추적

배틀은 실시간 WebSocket 통신에 크게 의존하기 때문에, 소켓 관련 에러를 체계적으로 추적하도록 했습니다.

WebSocket 연결 에러

Socket.io에서.제공하는 서버와 연결이 끊겼을 때 클라로 송신해주는 connect_error 이벤트, 재연결을 3번 시도했는데도 실패하면 송신 해주는 reconnect_failed 이벤트 수신 받은 경우 각각 추적하도록 했습니다.

우리 서버에서 제공 해주는 개별 소켓 에러 이벤트

클라이언트가 서버로 소켓 이벤트를 보냈는데, 서버에서 비즈니스 로직을 처리하다가 실패 한 경우 내려주는 총 8가지 에러 이벤트가 있는데 해당 이벤트들 마다 발생시 Sentry.captureException()을 호출해서 에러를 전송하도록 했습니다:
*battle:join:error

  • battle:attack:error
  • battle:defense:error
  • battle:attack:vote:error
  • battle:defense:vote:error
  • battle:chat:error
  • battle:team:vote:error
  • battle:user:skip:error

기대 효과

네트워크 불안정이나 서버 부하로 인한 연결 문제 패턴을 분석할 수 있고, 비즈니스 에러의 발생 빈도와 시간대별 패턴을 파악할 수 있습니다.


4. Breadcrumb을 통한 에러 발생전 사용자 타임라인 추적

. Sentry Breadcrumb을 활용해서 주요 이벤트들을 시간 순서대로 기록하게 하여 에러가 발생하여 Sentry로 로그를 보낼 떄 같이 보내게 하여 에러가 발생하기전 게임 진행 상황 정보/ 소켓 플로우를 파악할 수 있게 했습니다. 물론 Sentry가 기본적으로 사용자가 어떤 인터렉션을 했고 어떤 api에서 에러가 발생했는지 알려주긴 하나 그 것만으로는 부족할 것 같아서요

Breadcrumb으로 기록한 이벤트:

  • WebSocket 연결 성공(connect) - battleId, socketId
  • WebSocket 재연결 성공(reconnect) - battleId
  • WebSocket 연결 끊김(disconnect) - battleId, reason, isOnline, isVisible
  • WebSocket 재연결 시도(reconnect_attempt) - battleId, attemptNumber
  • 배틀 페이즈 변경(battle:phase:updated) - phase, round
  • 배틀 라운드 변경(battle:round:updated) - round, topic
  • 사용자 팀 변경(battle:team:updated) - battleId, team

전송 받을 BreadCrumb 예시

[14:30:15] WebSocket connected
[14:30:20] 배틀 라운드 변경 - Round 1 (topic: "...")
[14:30:25] 배틀 페이즈 변경 - attack
[14:32:45] 배틀 페이즈 변경 - defense
[14:35:10] 배틀 페이즈 변경 - vote
[14:37:00] 배틀 라운드 변경 - Round 2


💬 질문사항 (고민했던 부분)

1. Breadcrumb 데이터의 적정 수준

이벤트별로 필요한 최소한의 데이터만 남기는 방향으로 정리했는데, 에러 분석에 더 필요한 정보가 있을지 궁금합니다.

2. 에러 레벨 분류 기준

핵심 기능 실패는 error, 부가 기능 실패는 warning으로 분류했는데, 이 기준이 적절한지 확인 부탁드립니다.

3. 추가 추적 범위

현재는 배틀 진행 중 발생하는 에러에 집중했는데, 로그인 실패나 배틀 정보 로드 실패 같은 진입 단계 에러도 추가하면 좋을 것 같습니다. 우선순위를 어떻게 가져가면 좋을까요?

@JuJangGwon JuJangGwon self-assigned this Feb 3, 2026
@JuJangGwon JuJangGwon added ⚙️ settings This issue or pull request already exists 🧑‍🎨 FE Good for newcomers labels Feb 3, 2026
@JuJangGwon JuJangGwon force-pushed the settings/#310-sentry branch from 8963142 to 16e3e68 Compare February 4, 2026 07:29
- @sentry/react 패키지 추가
- 개발/프로덕션 환경별 활성화 제어
- VITE_SENTRY_DSN, VITE_ENABLE_SENTRY 환경변수 추가
- React 에러 자동 캡처 및 Sentry 전송
- 에러 발생 컴포넌트, URL, timestamp 등 메타데이터 추가
- SectionErrorBoundary의 에러 같은 경우에는 특정 섹션만 고장나고 앱은
  계속 동장하기에 level Warning으로 마킹
- SectionErrorBoundary로 감싼 컴포넌트에서 생긴 에러 자동 캡처 및 Sentry 전송(주로 API 페칭 영역일듯)
- 에러 발생 컴포넌트, URL, timestamp 등 메타데이터 추가
- wrapCreateBrowserRouterV6로 라우팅 에러 자동 캡처 기능 추가
- React router가 라우팅 전역 에러를 캐치한 경우 errorPage 컴포넌트를 렌더링하는데, 이 errorPage에 센트리 caputreException을 추가하여 Router 에러 트레킹
- 에러바운더리에 캐치되기 위해서는 꼭 필요한 옵션인데  아마 누락되어있었던 것 같아, true로 설정했습니다
>>
>> - 게스트 로그인 / Oauth 로그인 각 케이스마다 구분하여 사용자 정보 설정 추가
>> - Oauth의 로그인의 경우 어느 provider를 이용했는지 정보 추가
>> - 로그인 시 자동등록, 로그아웃 시 자동 제거 로직 적용
>> - AuthStore 타입에 provider 필드 추가 (github | kakao)
- connect_error 이벤트를 Sentry로 전송하여 실시간 추적
- 소켓 상태 및 배틀 정보를 컨텍스트로 포함
- reconnect_failed 이벤트를 Sentry로 전송
- 3번 재연결 시도 실패 시 에러 로깅
>>
>> - connect, reconnect, disconnect, reconnect_attempt 이벤트에 breadcrumb 추가
>> - 에러 발생 시 이벤트 타임라인 추적 용도
- battle:phase:updated 이벤트에 breadcrumb 추가
- battle:round:updated 이벤트에 breadcrumb 추가
- battle:join:error - 배틀 입장 실패
- battle:attack:error - 공격 제출 실패
- battle:defense:error - 방어 제출 실패
- battle:attack:vote:error - 공격 투표 실패
- battle:defense:vote:error - 방어 투표 실패
- battle:chat:error - 채팅 전송 실패
- battle:team:vote:error - 팀 투표 실패
- battle:user:skip:error - 스킵 요청 실패
- battle:team:updated 이벤트에 breadcrumb 추가
@JuJangGwon JuJangGwon force-pushed the settings/#310-sentry branch from 16e3e68 to 47ee9f1 Compare February 4, 2026 07:39
@JuJangGwon JuJangGwon force-pushed the settings/#310-sentry branch from 47ee9f1 to e43e7c3 Compare February 4, 2026 07:42
@JuJangGwon JuJangGwon merged commit cddead6 into dev Feb 4, 2026
2 checks passed
@JuJangGwon JuJangGwon deleted the settings/#310-sentry branch February 4, 2026 07:46
HoonDongKang pushed a commit that referenced this pull request Feb 4, 2026
* feat: Sentry 패지키 설치 및 환경 세팅

- @sentry/react 패키지 추가
- 개발/프로덕션 환경별 활성화 제어
- VITE_SENTRY_DSN, VITE_ENABLE_SENTRY 환경변수 추가

* feat: GlobalErrorBoundary에 Sentry 에러 추적 연동

- React 에러 자동 캡처 및 Sentry 전송
- 에러 발생 컴포넌트, URL, timestamp 등 메타데이터 추가

* feat: SectionErrorBoundary에 Sentry 에러 추적 연동

- SectionErrorBoundary의 에러 같은 경우에는 특정 섹션만 고장나고 앱은
  계속 동장하기에 level Warning으로 마킹
- SectionErrorBoundary로 감싼 컴포넌트에서 생긴 에러 자동 캡처 및 Sentry 전송(주로 API 페칭 영역일듯)
- 에러 발생 컴포넌트, URL, timestamp 등 메타데이터 추가

* settings : Sentry  발생시 Replay 녹화 기능 설정

* feat : GlobalErrorBoundary 제거 및 React Router에 Sentry에러 트래킹 통합

- wrapCreateBrowserRouterV6로 라우팅 에러 자동 캡처 기능 추가
- React router가 라우팅 전역 에러를 캐치한 경우 errorPage 컴포넌트를 렌더링하는데, 이 errorPage에 센트리 caputreException을 추가하여 Router 에러 트레킹

* fix : useGetBattleInfo 훅에서 throwonError 옵션을 true로 설정

- 에러바운더리에 캐치되기 위해서는 꼭 필요한 옵션인데  아마 누락되어있었던 것 같아, true로 설정했습니다

* feat : Sentry 사용자 컨텍스 트 정보 설정 추가
>>
>> - 게스트 로그인 / Oauth 로그인 각 케이스마다 구분하여 사용자 정보 설정 추가
>> - Oauth의 로그인의 경우 어느 provider를 이용했는지 정보 추가
>> - 로그인 시 자동등록, 로그아웃 시 자동 제거 로직 적용
>> - AuthStore 타입에 provider 필드 추가 (github | kakao)

* feat: WebSocket 연결 실패 Sentry 모니터링 추가

- connect_error 이벤트를 Sentry로 전송하여 실시간 추적
- 소켓 상태 및 배틀 정보를 컨텍스트로 포함

* feat: WebSocket 재연결 3번 실패시 Sentry 로그 보내는 로직 추가

- reconnect_failed 이벤트를 Sentry로 전송
- 3번 재연결 시도 실패 시 에러 로깅

* feat: WebSocket 생명주기 이 벤트에 Sentry Breadcrumb 추가
>>
>> - connect, reconnect, disconnect, reconnect_attempt 이벤트에 breadcrumb 추가
>> - 에러 발생 시 이벤트 타임라인 추적 용도

* feat: 배틀 페이즈/라운드 변경 Sentry Breadcrumb 추가

- battle:phase:updated 이벤트에 breadcrumb 추가
- battle:round:updated 이벤트에 breadcrumb 추가

* feat: 서버 소켓 에러 이벤트 Sentry 추적 추가

- battle:join:error - 배틀 입장 실패
- battle:attack:error - 공격 제출 실패
- battle:defense:error - 방어 제출 실패
- battle:attack:vote:error - 공격 투표 실패
- battle:defense:vote:error - 방어 투표 실패
- battle:chat:error - 채팅 전송 실패
- battle:team:vote:error - 팀 투표 실패
- battle:user:skip:error - 스킵 요청 실패

* feat: 팀 변경 Sentry Breadcrumb 추가

- battle:team:updated 이벤트에 breadcrumb 추가

* fix : OauthStore에서 유저 토큰이 없는경우 리프레시 토큰을 받아오는 로직 제거

* test: Vitest테스트 환경에 sentry 모킹 설정 추가

* test : 임시 문제되는 테스트 제거
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧑‍🎨 FE Good for newcomers ⚙️ settings This issue or pull request already exists 🎯 task

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Settings] Frontend 에러 모니터링 툴 Sentry를 도입한다.

3 participants