Sentry란?
Sentry
- 실시간 로그 취합 및 분석 도구이자 모니터링 플랫폼 이다.
- 애플리케이션의 오류 추적과 성능 모니터링을 제공하는 강력한 APM 도구
- Application Performance Monitoring 도구
- 애플리케이션 성능 모니터링
- 센트리는 Error Monitoring 도구이자 APM인 것
왜 나왔나?
프로덕션 환경에서 실제로 터지는 오류를 개발자가 알 수 없기 때문
에러도 관측 대상이라는 인식이 등장하면서 Sentry가 그 표준 도구로 자리잡음
1. 기존 문제 상황
- 개발 환경 중심 디버깅의 한계
- 보통 위에서만 확인
- 하지만 실제 사용자 환경은 천차만별
- 제 컴퓨터에서는 오류 안나는데용?
- 프로덕션 오류는 로그로만 추적
- 서버
- 클라이언트
- 오류는 이미 사용자에게 발생 BUT 개발자는 이후에 알게됨
- 오류의 맥락 부족
- 기존 로그는 정보가 부족했음
- 어떤 유저가?
- 어떤 행동을 했을 때?
- 어떤 브라우저/OS에서?
- 어떤 요청 파라미터로?
- 재현이 불가능한 경우 다수
2. 핵심 문제
- 실제 사용자 환경에서 발생한 오류를 상황 재현 없이 바로 원인을 알 수 없을까
3. 문제 해결 아이디어
- 프로덕션 중심 에러 트래킹
- 실제 사용자가 사용하는 프로덕션에서 에러가 발생하는 즉시 수집
- 서버 / 브라우저 / 앱 모두 대상
- Stack Trace + Context 자동 수집
- 에러 하나에 다음 정보가 담김
- stack trace
- 💡 stack trace? ⇒ 에러가 발생했을 때, 그 에러가 발생하기까지 거쳐온 함수 호출 경로
- 위에서 아래로 읽으면
- 맨 위는 에러가 실제로 발생한 함수
- 아래는 그 함수들을 호출한 상위 함수들
Stack Trace:
at calculateTotal (order.js:2:10) ← 실제 에러 발생 위치
at processOrder (order.js:6:17) ← 여기서 calculateTotal 호출
at checkout (order.js:10:10) ← 여기서 processOrder 호출
at main (app.js:45:5) ← 여기서 checkout 호출
- 사용자 행동 breadcrumb
특징
- 개발자 친화적인 에러 리포트
- 정확한 에러 발생 위치와 stack trace 제공
- 소스맵 지원으로 실제 코드 라인 추적 가능
- 에러 발생 시점의 상태와 환경 정보 상세 제공
- 실시간성
- 에러 발생 즉시 알림 가능
- 이슈의 발생 빈도와 영향도 실시간 모니터링
- 신속한 대응이 가능한 환경 제공
- 개발 워크플로우 통합
- Github 등 개발 도구들과의 쉬운 연동
- CI/CD 파이프라인에 통합 가능
- 팀 협업 도구들과의 원활한 연동
도입 배경 (나중에 발표할때 쓰면 좋을듯 ㅋㅋ)
적용 방법 및 분석
Sentry 설정 과정 상세 설명
1단계: Sentry SDK 설치
npm install @sentry/react @sentry/vite-plugin
- @sentry/react: React 애플리케이션에서 에러 추적을 위한 Sentry SDK
- @sentry/vite-plugin: Vite 빌드 시 소스맵을 Sentry에 자동 업로드하는 플러그인
2단계: Vite 설정 파일 수정
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { sentryVitePlugin } from "@sentry/vite-plugin"
export default defineConfig({
plugins: [
react(),
sentryVitePlugin({
org: "o4510636141117440",
project: "4510636143017984",
}),
],
build: {
sourcemap: true, // 소스맵 생성 활성화
},
})
- sentryVitePlugin: 빌드 시 소스맵을 Sentry에 업로드 (배포된 코드의 에러를 원본 소스로 매핑)
- sourcemap: true: 프로덕션 빌드에서도 소스맵 생성 (디버깅용)
- org와 project: Sentry 조직 및 프로젝트 ID
3단계: Sentry 초기화 코드 추가
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://85f25a8ced07e53a264d3ceab811c45e@o4510636141117440.ingest.us.sentry.io/4510636186337280",
integrations: [
Sentry.browserTracingIntegration(), // 성능 모니터링
Sentry.replayIntegration(), // 세션 리플레이
],
tracesSampleRate: 1.0, // 100% 성능 트랜잭션 수집
tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
replaysOnErrorSampleRate: 1.0, // 100% 에러 세션 녹화
});
- dsn: Sentry 프로젝트 고유 주소 (Data Source Name)
- browserTracingIntegration(): 페이지 로딩 시간, API 호출 속도 등 성능 추적
- replayIntegration(): 사용자 행동을 비디오처럼 재생 가능
- tracesSampleRate: 1.0: 모든 트랜잭션 수집 (프로덕션에서는 0.1~0.3 권장)
- tracePropagationTargets:
- 프론트엔드 → API 호출 → 백엔드 전체 과정을 하나의 트랜잭션으로 추적
- 에러가 어떤 API 호출에서 발생했는지 연결해서 볼 수 있음
- replaysOnErrorSampleRate: 1.0: 에러 발생 시 100% 녹화
4단계: 에러 발생 코드 및 센트리 코드 추가
4-1. 사용자 입력 검증 에러 (Validation Error)
코드
const handleSubmit = () => {
try {
// 특수문자 체크를 안했다고 가정
if (/[!@#$%^&*(),.?":{}|<>]/.test(username)) {
const error = new Error(`유효하지 않은 사용자명: 특수문자가 포함되어 있습니다`)
// Sentry에 에러 컨텍스트와 함께 전송
Sentry.captureException(error, {
tags: {
error_type: 'validation_error',
input_field: 'username'
},
extra: {
username_input: username,
email_input: email,
validation_failed: 'special_characters'
},
level: 'error'
})
setErrorMessage('❌ 전송 실패: 사용자명에 특수문자를 사용할 수 없습니다')
- Sentry.captureException(): 에러를 Sentry에 전송
- tags: 에러를 필터링/그룹화할 수 있는 태그 (예: error_type: validation_error)
- extra: 디버깅에 도움되는 추가 정보 (실제 사용자 입력값 등)
- level: 에러 심각도 (error, warning, info 등)
4-2. 런타임 에러
const throwError = () => {
throw new Error("예기치 않은 런타임 에러가 발생했습니다!")
}
- JavaScript Error 객체를 던지면 Sentry가 자동으로 캡처
- 별도로 captureException() 호출 불필요
4-3. 정보성 메시지
const captureMessage = () => {
Sentry.captureMessage("사용자가 메시지 전송 버튼을 클릭했습니다", "info")
}
- 에러가 아닌 일반 로그 메시지 전송
- 사용자 행동 추적이나 중요 이벤트 기록용
5단계: 개발 서버 실행
6단계: 테스트 방법
테스트 시나리오 1: 사용자 입력 검증 에러
- 사용자명에 특수문자 입력 (예: user!@#)
- 등록하기 클릭
- Sentry 대시보드에서 확인:
- 에러 메시지: "유효하지 않은 사용자명: 특수문자가 포함되어 있습니다"
- 태그: error_type: validation_error, input_field: username
- 추가 정보: 실제 입력한 사용자명과 이메일
테스트 시나리오 2: 이메일 형식 에러
- 이메일에 @ 없이 입력 (예: test)
- 등록하기 클릭
- Sentry 대시보드에서 확인:
- 에러 메시지: "유효하지 않은 이메일 형식"
- 레벨: Warning
- 태그: input_field: email
테스트 시나리오 3: 정상 등록
- 올바른 형식 입력 (예: 사용자명: john, 이메일: john@example.com)
- 등록하기 클릭
- Sentry 대시보드에서 확인:
- Info 메시지: "사용자 등록 성공"
- 태그: action: user_registration
테스트 시나리오 4: 런타임 에러
- 일반 에러 발생시키기 버튼 클릭
- Sentry 대시보드에서 확인:
- 에러 메시지: "예기치 않은 런타임 에러가 발생했습니다!"
- 스택 트레이스
- 에러 발생 시점의 사용자 세션 리플레이
테스트 시나리오 5: 정보성 메시지
- Info 메시지 전송하기 버튼 클릭
- Sentry 대시보드에서 확인:
- Info 메시지: "사용자가 메시지 전송 버튼을 클릭했습니다"
Sentry 대시보드에서 확인할 수 있는 정보
- 에러 발생 횟수
- 영향받은 사용자 수
- 스택 트레이스
- 태그별 필터링 (예: error_type: validation_error)
- 페이지 로딩 시간
- API 호출 속도
- 느린 트랜잭션 식별
- 에러 발생 직전 사용자 화면 재생
- 마우스 이동, 클릭, 스크롤 등 모든 행동 확인
- 어떤 순서로 버튼을 눌렀는지 시각적으로 확인
| 컬럼 | 의미 |
| Issue | 에러 제목 및 발생 위치 |
| Last Seen | 마지막으로 발생한 시간 |
| Age | 에러가 처음 발생한 후 경과 시간 |
| Trend | 발생 추세 (New/Regressed/Ongoing) |
| 24h / 14d | 24시간 / 14일간 발생 횟수 그래프 |
| Events | 총 발생 횟수 |
| Users | 영향받은 사용자 수 |
| Priority | 우선순위 |
| Assignee |
상단 헤더
- 상태: New (처음 발생한 에러)
- 이벤트 수: 2회 발생
- 영향받은 사용자: 0명 (익명 사용자 90일 기준)
- Replay: 1개의 세션 리플레이 녹화 있음
주요 버튼
- Resolve: 이슈 해결 완료 표시
- Archive: 보관 (중요하지 않은 에러)
- Priority: 우선순위 설정
- Assignee: 담당자 지정
이벤트 타임라인
- Events: 2 - 총 2번 발생
- Users: 0 - 영향받은 사용자 0명
- 오후 3시 ~ 6시 사이 발생 추이
- Jan 1 5:00 PM에 발생 집중 (회색 막대)
오른쪽 태그 정보
Tags (에러와 관련된 메타데이터)
| 태그 | 값 | 비율 |
| browser | Chrome Mobile 143... | 50% |
| url | localhost:5174/ | 100% |
| environment | production | 100% |
| mechanism | generic | 100% |
- 브라우저: Chrome Mobile에서 발생
- URL: localhost:5174에서 발생
- 환경: production 환경 ⇒ 설정하지 않으면 기본값
- mechanism: generic (일반적인 에러 캡처 방식)
상단 정보
- an hour ago - 1시간 전 발생
- JSON / Copy as Markdown - 데이터 내보내기 옵션
Frontend 정보
- Chrome Mobile 143.0.0 - 브라우저
- Android 6.0 - 운영체제
- production - 환경
Highlights (주요 정보)
왼쪽 컬럼
| 항목 | 값 |
| handled | yes |
| level | warning |
- handled: yes - 에러가 try-catch로 처리됨 (src/App.tsx:78-80)
- level: warning - Warning 레벨 (src/App.tsx:56에서 설정)
오른쪽 컬럼
- url - 에러 발생한 페이지 주소
- Trace ID - 성능 추적 ID (클릭하면 전체 트랜잭션 확인 가능)
Stack Trace란?
에러가 어디서 발생했는지 역순으로 추적한 경로입니다. 가장 위에 있는 것이 에러 발생 지점입니다.
화면 분석
상단 정보
- mechanism: generic - 일반적인 에러 캡처
- handled: true - try-catch로 처리됨
Stack Trace 본문
/src/App.tsx in handleSubmit at line 38:23
- 파일: /src/App.tsx
- 함수: handleSubmit
- 라인: 38번째 줄, 23번째 문자
- In App: 여러분의 앱 코드 (라이브러리 코드가 아님)
실제 코드 위치: src/App.tsx:44에서 에러 생성:
const error = new Error("유효하지 않은 이메일 형식")
호출 경로 (Call Stack)
Called from: /node_modules/vite/deps/react-dom_client.js in executeDispatch
- handleSubmit 함수가 React DOM의 executeDispatch에서 호출됨
- "Show 7 more frames" - 클릭하면 전체 호출 경로 표시
전체 흐름 (역순)
사용자 버튼 클릭
↓
React 이벤트 핸들러 실행 (executeDispatch)
↓
handleSubmit 함수 실행 (App.tsx:14)
↓
이메일 검증 실패 (App.tsx:43)
↓
Error 생성 (App.tsx:44) ← 여기서 에러 발생!
우측 버튼들
- Most Relevant: 가장 중요한 프레임만 표시 (현재 선택)
- Full Stack Trace: 모든 호출 경로 표시
- Newest: 최신 순 정렬
실제 활용
- 어느 파일: /src/App.tsx
- 어느 함수: handleSubmit
- 몇 번째 줄: 38번 (실제로는 44번 - Sentry가 빌드된 코드 기준으로 표시)
Session Replay
- 가장 중요한 기능
- 해당 에러가 발생한 시점에 대해 사용자가 어떤 행동을 했는지 녹화해서 보여줌
- 사용자가 어떤 상황에서 에러가 발생했는지에 대한 전달이 되지 않았음에도 에러 발생 상황 파악 및 해결 가능
Breadcrumbs
에러 발생 직전에 사용자가 한 행동들을 시간 순서대로 기록한 것
Breadcrumbs 읽는 법
아래에서 위로 읽으면 됨 (오래된 것 → 최신 순)
1. Console warning (6:21:52.299 PM)
- 타입: Console 경고
- 의미: 개발 도구 메시지 (무시 가능)
2. Console debug (6:21:52.316 PM)
[vite] connected.
{ arguments: [ 1 item ], logger: console }
- 타입: Console 디버그
- 의미: Vite 개발 서버 연결됨
3. Sentry Transaction (6:21:53.353 PM)
63912e0ac1a040e8a1ffaff07169e8da
- 타입: Sentry 성능 추적
- 의미: 페이지 로딩/네비게이션 트랜잭션 시작
- Transaction ID: 클릭하면 성능 상세 정보 확인 가능
4. UI Click (6:21:53.481 PM) ⭐ 중요!
body > div#root > div.card > div > button.message-button
- 타입: 사용자 클릭
- 클릭한 요소: .message-button 버튼
- 의미: "Info 메시지 전송하기" 버튼 클릭 (src/App.tsx:225)
5. Message (6:21:53.482 PM) ⭐ 발생!
- 타입: Info 메시지
- 의미: src/App.tsx:88에서 전송한 메시지
HTTP Request 섹션은 에러 발생 시점의 HTTP 요청 정보
- 현재는 / 링크에서 페이지 읽어오는 요청밖에 없음
- API 호출로 인한 통신이 많이 발생하는 경우에는 중요!
- 어떤 요청이 발생하던 시점인지 파악 가능한 중요한 곳
Tags 섹션은 에러와 관련된 메타데이터를 태그 형태로 확인
화면 분석
왼쪽 컬럼
| 태그 키 | 값 | 의미 |
| browser | Chrome 143.0.0 | 브라우저 버전 |
| name | Chrome | 브라우저 이름 |
| environment | production | 실행 환경 |
| level | info | 로그 레벨 |
오른쪽 컬럼
Custom 태그 확인하기
Custom 탭에서는 코드에서 직접 설정한 커스텀 태그들만 확인 가능
Sentry.captureMessage("사용자 등록 성공", {
level: "info",
tags: {
action: "user_registration", // ← 이게 Custom 태그!
}
})
실제 활용
1. 에러 필터링
- error_type:validation_error 검색 → 모든 검증 에러만 표시
- browser:Chrome 검색 → Chrome에서 발생한 에러만 표시
2. 그룹화 및 분석
- "어떤 브라우저에서 에러가 많이 발생하나?"
- "어떤 input 필드에서 에러가 많나?"
- "production vs development 환경 비교"
3. 알림 규칙 설정
error_type = "validation_error" AND input_field = "email"
Contexts 섹션은 에러 발생 환경에 대한 상세 정보
왼쪽 컬럼
1. User (사용자 정보)
Geography: Anyang-si, South Korea (KR)
- 위치: 한국 안양시
- 의미: 사용자의 지리적 위치 (IP 기반)
2. Browser (브라우저 정보)
Name: Chrome
Version: 143.0.0
3. Operating System (운영체제)
Name: Windows
Version: >=10
- OS: Windows
- 버전: Windows 10 이상
오른쪽 컬럼
4. React (프레임워크)
- React 버전: 19.2.3 (package.json:15에서 설정)
5. Trace Details (추적 정보)
Client Sample Rate: 1
Span ID: 96f3a7c7f59e434e
Status: unknown
Trace ID: 3d895fb934e54a9d897b6ac80858e192
- Client Sample Rate: 클라이언트 샘플링 비율 (1 = 100%)
- Span ID: 현재 작업의 고유 ID
- Status: 트레이스 상태 (unknown/ok/error 등)
- Trace ID: 전체 트랜잭션 추적 ID (클릭 시 성능 상세 페이지로 이동)
실제 활용
1. 지역별 에러 분석
"한국에서만 이 에러가 발생하나?"
→ Geography 확인
2. 환경별 버그 재현
"Chrome 143에서만 발생하는 버그인가?"
→ Browser 정보 확인
3. 프레임워크 버전 이슈
"React 19에서 추가된 기능이 문제인가?"
→ React Version 확인
4. 성능 추적
Trace ID 클릭 → 전체 트랜잭션 흐름 확인
- 페이지 로드 시간
- API 호출 시간
- 렌더링 시간
- 에러가 발생한 곳에 입력된 데이터와 어떤 에러인지 확인하는 extra 데이터를 여기서 확인 가능
extra: {
username_input: username,
email_input: email,
validation_failed: "special_characters",
},
실제 프로덕션 환경에서 발생하는 에러들을 주축으로 캡쳐할 에러들 태그를 설정해놓고, 어떤 부분에서 어떤 에러들이 발생하는지에 대한 기록을 기반으로 해결 및 개선이 더 중요하다고 생각하여 실제 프로젝트에 적용하고 팀 단위로 진행하는 부분으로 센트리 2 작성 예정