Sentry: 실시간 에러 모니터링 및 성능 추적 플랫폼
📋 문서 분석
- 문서 유형: Explanation (개념 설명) + Tutorial (실습 가이드)
- 대상 독자: 초급~중급 프론트엔드 개발자
- 주요 목표: Sentry의 개념을 이해하고 프로젝트에 적용할 수 있음
- 예상 길이: 중간~긺
개요
Sentry는 실시간으로 애플리케이션의 에러를 추적하고 성능을 모니터링하는 오픈소스 플랫폼입니다. 프로덕션 환경에서 발생하는 예외, 크래시, 성능 병목 현상을 자동으로 수집하고 분석하여 문제를 빠르게 파악하고 해결할 수 있게 도와줍니다.
이 문서에서는 Sentry가 무엇인지, 왜 필요한지, 그리고 실제 프로젝트에 어떻게 적용하는지 알아봅니다.
배경
왜 필요한가?
전통적인 개발 방식에서는 다음과 같은 문제가 있었습니다:
사용자가 겪는 문제를 개발자가 모른다
- 사용자 브라우저에서 발생한 에러는 개발자에게 전달되지 않습니다
- 콘솔 로그는 사용자의 로컬 환경에만 남고 사라집니다
- 버그 리포트는 재현이 어렵고 정보가 불완전합니다
에러 디버깅이 어렵다
- 어떤 환경에서 에러가 발생했는지 알 수 없습니다
- 에러 발생 직전의 사용자 행동을 파악할 수 없습니다
- 스택 트레이스만으로는 원인을 찾기 힘듭니다
성능 문제를 감지하기 어렵다
- 특정 API 호출이 느린지 알 수 없습니다
- 어떤 페이지에서 렌더링이 지연되는지 모릅니다
- 데이터베이스 쿼리의 성능을 측정할 방법이 없습니다
등장 이전의 방식
Sentry가 등장하기 전에는 다음과 같은 방법을 사용했습니다:
// ❌ 기존 방식: 수동 에러 처리
window.onerror = function(message, source, lineno, colno, error) {
// 에러 정보를 서버로 전송
fetch('/api/log-error', {
method: 'POST',
body: JSON.stringify({
message,
source,
lineno,
colno,
stack: error?.stack
})
});
};이 방식의 문제점:
- 모든 에러 처리 로직을 직접 구현해야 합니다
- 에러 그룹핑, 중복 제거, 알림 등의 기능이 없습니다
- 성능 데이터는 별도로 수집해야 합니다
- 에러 분석 도구가 없어 원시 데이터만 확인할 수 있습니다
동작 원리
핵심 메커니즘
Sentry는 다음과 같은 과정으로 에러를 수집하고 처리합니다:
- SDK 초기화: 애플리케이션에 Sentry SDK를 설치하고 설정합니다
- 자동 계측: SDK가 전역 에러 핸들러를 등록하고 에러를 자동으로 캡처합니다
- 데이터 수집: 에러 발생 시 스택 트레이스, 사용자 정보, 브라우저 환경 등을 수집합니다
- 전송: 수집된 데이터를 Sentry 서버로 전송합니다
- 분석 및 그룹핑: 유사한 에러를 자동으로 그룹화하고 패턴을 분석합니다
- 알림: 새로운 에러나 중요한 문제가 발생하면 팀에 알립니다
시각적 흐름
[사용자 브라우저]
↓
에러 발생
↓
[Sentry SDK 캡처]
↓
컨텍스트 수집
- 스택 트레이스
- 사용자 정보
- 브레드크럼 (행동 추적)
- 환경 정보
↓
[Sentry 서버]
↓
에러 그룹핑
↓
대시보드 표시
↓
[개발자 알림]
- 이메일
- Slack
- Jira 이슈 생성코드로 이해하기
// Sentry가 자동으로 처리하는 예제
import * as Sentry from "@sentry/react";
// 1. 초기화
Sentry.init({
dsn: "https://your-dsn@sentry.io/project-id",
environment: "production",
tracesSampleRate: 1.0, // 성능 모니터링
});
// 2. 자동 에러 캡처 - 별도 코드 없이 작동
function UserProfile({ userId }) {
// 이 에러는 자동으로 Sentry에 전송됩니다
const user = fetchUser(userId); // null 체크 없이 접근
return <div>{user.name}</div>; // TypeError 발생 시 자동 캡처
}
// 3. 수동 에러 캡처 (필요 시)
try {
processPayment(amount);
} catch (error) {
Sentry.captureException(error, {
tags: {
payment_method: "credit_card",
amount: amount
}
});
throw error;
}주요 기능
기능 1: 에러 모니터링 (Error Monitoring)
애플리케이션에서 발생하는 모든 예외를 자동으로 추적합니다.
자동 수집 정보:
- 스택 트레이스: 에러가 발생한 정확한 위치
- 소스맵 지원: 빌드된 코드를 원본 코드로 변환
- 에러 그룹핑: 동일한 근본 원인을 가진 에러를 하나로 묶음
- 영향도 측정: 얼마나 많은 사용자가 영향을 받았는지
// 예시: React 컴포넌트 에러
function ProductList() {
const products = useProducts();
// products가 undefined일 때 에러 발생
return products.map(product => (
<ProductCard key={product.id} {...product} />
));
}
// Sentry가 자동으로 캡처하는 정보:
// - TypeError: Cannot read property 'map' of undefined
// - 발생 위치: ProductList.jsx:4
// - 영향받은 사용자 수: 127명
// - 첫 발생 시간: 2024-01-15 14:23기능 2: 브레드크럼 (Breadcrumbs)
에러 발생 직전의 사용자 행동을 타임라인으로 기록합니다.
// 자동으로 기록되는 브레드크럼:
// 1. [14:20:15] User clicked "Add to Cart" button
// 2. [14:20:16] API call: POST /api/cart/add
// 3. [14:20:17] Navigation: /cart → /checkout
// 4. [14:20:18] User clicked "Complete Purchase"
// 5. [14:20:19] ❌ Error: Payment processing failed
// 수동으로 브레드크럼 추가
Sentry.addBreadcrumb({
category: 'payment',
message: 'User selected payment method: Credit Card',
level: 'info'
});이 기능으로 에러 재현이 쉬워집니다.
기능 3: 성능 모니터링 (Performance Monitoring)
애플리케이션의 성능을 측정하고 병목 지점을 찾습니다.
// 자동 성능 추적
Sentry.init({
dsn: "...",
tracesSampleRate: 1.0, // 100% 트랜잭션 추적
integrations: [
new Sentry.BrowserTracing({
// 페이지 로드 시간
// API 호출 시간
// 컴포넌트 렌더링 시간
}),
],
});
// 수동 성능 측정
const transaction = Sentry.startTransaction({
name: "processCheckout",
op: "checkout"
});
const span = transaction.startChild({
op: "payment",
description: "Process payment"
});
await processPayment();
span.finish();
transaction.finish();
// Sentry 대시보드에서 확인 가능:
// - processCheckout 평균 시간: 2.3초
// - payment 단계 시간: 1.8초 (병목!)
// - 가장 느린 트랜잭션 상위 10개기능 4: 릴리스 추적 (Release Tracking)
배포 버전별로 에러를 추적하여 회귀 버그를 빠르게 감지합니다.
// 빌드 시 릴리스 정보 설정
Sentry.init({
dsn: "...",
release: "my-app@1.2.0",
environment: "production"
});
// 대시보드에서 확인:
// - v1.2.0 배포 후 새로운 에러 3건 발견
// - v1.1.0에서는 발생하지 않았던 에러
// - 영향받은 사용자: 45명
// → 즉시 롤백 또는 핫픽스 배포 결정실제 사용 사례
사례 1: React 애플리케이션에 Sentry 통합
프론트엔드 React 프로젝트에 Sentry를 적용하는 전형적인 사례입니다.
// 1. 설치
// npm install @sentry/react
// 2. 초기화 (src/index.js 또는 main.tsx)
import React from "react";
import ReactDOM from "react-dom/client";
import * as Sentry from "@sentry/react";
import App from "./App";
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
environment: process.env.NODE_ENV,
// 성능 모니터링 설정
integrations: [
new Sentry.BrowserTracing({
// React Router 통합
routingInstrumentation: Sentry.reactRouterV6Instrumentation(
React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes
),
}),
new Sentry.Replay(), // 세션 리플레이
],
tracesSampleRate: 0.1, // 10%의 트랜잭션 추적
replaysSessionSampleRate: 0.1, // 10%의 세션 녹화
replaysOnErrorSampleRate: 1.0, // 에러 발생 시 100% 녹화
// 개발 환경에서는 비활성화
enabled: process.env.NODE_ENV === 'production',
// 민감한 정보 필터링
beforeSend(event) {
// 개인정보가 포함된 에러는 전송하지 않음
if (event.user?.email) {
delete event.user.email;
}
return event;
}
});
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);사례 2: Next.js 애플리케이션 (App Router)
Next.js 14 App Router에서 Sentry를 설정하는 방법입니다.
// 설치
// npm install @sentry/nextjs
// sentry.client.config.js
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
debug: false,
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
integrations: [
new Sentry.Replay({
maskAllText: true,
blockAllMedia: true,
}),
],
});
// sentry.server.config.js
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
debug: false,
});
// app/error.tsx - 에러 바운더리
'use client';
import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<div>
<h2>문제가 발생했습니다</h2>
<button onClick={() => reset()}>다시 시도</button>
</div>
);
}사례 3: API 호출 에러 추적
네트워크 요청 실패를 상세하게 추적하는 방법입니다.
// API 클라이언트에 Sentry 통합
import * as Sentry from "@sentry/react";
async function apiRequest(endpoint, options) {
const transaction = Sentry.startTransaction({
name: `API ${options.method} ${endpoint}`,
op: "http.client"
});
try {
const response = await fetch(`/api${endpoint}`, {
...options,
headers: {
...options.headers,
'sentry-trace': transaction.toTraceparent(),
}
});
if (!response.ok) {
// HTTP 에러를 Sentry에 기록
Sentry.captureException(
new Error(`API Error: ${response.status}`),
{
tags: {
endpoint,
status_code: response.status,
method: options.method
},
contexts: {
response: {
status: response.status,
statusText: response.statusText,
url: response.url
}
}
}
);
}
transaction.setStatus('ok');
return await response.json();
} catch (error) {
transaction.setStatus('internal_error');
// 네트워크 에러를 Sentry에 기록
Sentry.captureException(error, {
tags: {
endpoint,
error_type: 'network_error'
}
});
throw error;
} finally {
transaction.finish();
}
}
// 사용 예시
try {
const data = await apiRequest('/users/123', { method: 'GET' });
console.log(data);
} catch (error) {
console.error('Failed to fetch user:', error);
}
// Sentry에서 확인 가능:
// - API GET /users/123: 평균 응답 시간 245ms
// - 실패율: 2.3% (주로 404 에러)
// - 가장 느린 요청: 1.2초 (타임아웃 경계)장점과 한계
장점
- ✅ 자동 에러 수집: 코드 수정 없이 대부분의 에러를 자동으로 캡처합니다
- ✅ 풍부한 컨텍스트: 에러 발생 시 사용자 행동, 환경 정보를 함께 수집합니다
- ✅ 스마트 그룹핑: 유사한 에러를 자동으로 묶어서 노이즈를 줄입니다
- ✅ 릴리스 추적: 버전별 에러를 추적하여 회귀 버그를 빠르게 발견합니다
- ✅ 성능 모니터링: 에러뿐만 아니라 성능 병목도 찾을 수 있습니다
- ✅ 다양한 통합: Slack, Jira, GitHub 등과 쉽게 연동됩니다
- ✅ 세션 리플레이: 에러 발생 순간의 사용자 화면을 녹화하여 재현이 쉽습니다
한계
- ⚠️ 비용: 무료 플랜은 이벤트 수 제한이 있고, 대규모 서비스는 비용이 높습니다
- ⚠️ 개인정보 처리: 사용자 데이터 수집 시 GDPR 등 규정을 준수해야 합니다
- ⚠️ 성능 오버헤드: SDK가 애플리케이션 성능에 미미하지만 영향을 줄 수 있습니다
- ⚠️ 소스맵 관리: 프로덕션 빌드에서 정확한 에러 위치를 표시하려면 소스맵 업로드가 필요합니다
- ⚠️ 노이즈: 샘플링 설정을 잘못하면 너무 많은 이벤트가 수집될 수 있습니다
트레이드오프
Sentry를 사용해야 하는 경우:
- 프로덕션 환경에서 사용자가 겪는 문제를 파악하고 싶을 때
- 팀이 여러 명이고 체계적인 에러 관리가 필요할 때
- 성능 모니터링이 필요한 복잡한 애플리케이션일 때
- 릴리스 품질을 데이터 기반으로 측정하고 싶을 때
Sentry가 불필요한 경우:
- 작은 개인 프로젝트나 프로토타입
- 로컬 개발 환경만 사용하는 경우
- 이벤트 수가 많아서 비용이 부담되는 경우 (자체 호스팅 고려)
시작하기
1단계: Sentry 계정 생성
- sentry.io 에 접속합니다
- 무료 계정을 생성합니다 (월 5,000 이벤트까지 무료)
- 새 프로젝트를 생성하고 플랫폼을 선택합니다 (React, Next.js 등)
- DSN(Data Source Name)을 복사합니다
2단계: SDK 설치
# React
npm install @sentry/react
# Next.js
npm install @sentry/nextjs
# Vanilla JavaScript
npm install @sentry/browser3단계: 기본 설정
// React 예시
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "YOUR_DSN_HERE",
environment: "production",
tracesSampleRate: 1.0,
});4단계: 테스트
// 테스트 에러 발생
function TestButton() {
return (
<button onClick={() => {
throw new Error("Sentry 테스트 에러!");
}}>
에러 발생
</button>
);
}버튼을 클릭하면 Sentry 대시보드에 에러가 표시됩니다.
5단계: 프로덕션 최적화
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
environment: process.env.NODE_ENV,
// 개발 환경에서는 비활성화
enabled: process.env.NODE_ENV === 'production',
// 샘플링 비율 조정 (비용 절감)
tracesSampleRate: 0.1, // 10%만 추적
// 민감한 데이터 필터링
beforeSend(event, hint) {
// PII 제거
if (event.request?.cookies) {
delete event.request.cookies;
}
return event;
},
// 특정 에러 무시
ignoreErrors: [
'ResizeObserver loop limit exceeded',
'Non-Error promise rejection captured',
],
});관련 개념
유사 도구
- LogRocket: 세션 리플레이에 더 특화되어 있으며, Sentry와 유사한 에러 추적 기능을 제공합니다
- Rollbar: Sentry와 유사한 에러 모니터링 도구로, 더 간단한 인터페이스를 제공합니다
- Bugsnag: 모바일 앱 에러 추적에 강점이 있는 도구입니다
대안
자체 구축: 작은 규모라면 AWS CloudWatch, Google Analytics 등으로 직접 구축할 수 있습니다
- 장점: 비용 절감, 완전한 제어
- 단점: 개발/유지보수 시간 필요, 기능 제한적
오픈소스 자체 호스팅: Sentry는 오픈소스이므로 직접 서버에 설치할 수 있습니다
- 장점: 데이터 완전 통제, 이벤트 수 제한 없음
- 단점: 서버 관리 필요, 업데이트 직접 처리
베스트 프랙티스
1. 환경별 설정 분리
// .env.development
REACT_APP_SENTRY_DSN=your-dsn-here
REACT_APP_SENTRY_ENVIRONMENT=development
REACT_APP_SENTRY_ENABLED=false
// .env.production
REACT_APP_SENTRY_DSN=your-dsn-here
REACT_APP_SENTRY_ENVIRONMENT=production
REACT_APP_SENTRY_ENABLED=true2. 사용자 컨텍스트 추가
// 로그인 후 사용자 정보 설정
Sentry.setUser({
id: user.id,
username: user.username,
// 이메일은 개인정보이므로 주의
// email: user.email,
});
// 로그아웃 시 사용자 정보 제거
Sentry.setUser(null);3. 커스텀 태그 활용
// 에러를 카테고리별로 분류
Sentry.setTag("payment_provider", "stripe");
Sentry.setTag("feature", "checkout");
// 에러 발생
try {
await processPayment();
} catch (error) {
Sentry.captureException(error, {
tags: {
payment_amount: amount,
currency: "USD"
}
});
}
// Sentry에서 태그별로 필터링 가능:
// - payment_provider: stripe인 에러만 보기
// - feature: checkout인 에러만 보기4. 알림 규칙 설정
Sentry 대시보드에서 알림 규칙을 설정하세요:
- 새로운 에러 발생: Slack으로 즉시 알림
- 에러 빈도 증가: 1분에 10건 이상 → 긴급 알림
- 릴리스 에러: 새 버전에서 에러 발생 → 팀 전체 알림
- 특정 태그: payment 관련 에러 → 결제팀에만 알림
문제 해결
증상 1: Sentry에 에러가 전송되지 않음
원인:
- DSN이 잘못 설정됨
enabled: false로 설정됨- 네트워크 차단 (방화벽, 광고 차단기)
해결 방법:
// 1. DSN 확인
console.log(Sentry.getCurrentHub().getClient()?.getDsn());
// 2. 테스트 에러 발생
Sentry.captureException(new Error("Test error"));
// 3. 브라우저 네트워크 탭에서 확인
// sentry.io로 요청이 전송되는지 확인
// 4. 개발 환경에서도 활성화 (테스트용)
Sentry.init({
dsn: "...",
enabled: true, // 개발 중에도 활성화
debug: true, // 디버그 로그 출력
});증상 2: 스택 트레이스가 난독화되어 읽을 수 없음
원인:
소스맵이 업로드되지 않아서 빌드된 코드의 위치만 표시됩니다.
해결 방법:
# Next.js는 자동으로 처리
# sentry.properties 파일 생성
org=your-org
project=your-project
# 빌드 시 소스맵 업로드
npx @sentry/cli releases files <release> upload-sourcemaps ./build증상 3: 너무 많은 이벤트로 할당량 초과
해결 방법:
// 1. 샘플링 비율 조정
Sentry.init({
tracesSampleRate: 0.1, // 10%만 추적
replaysSessionSampleRate: 0.1,
});
// 2. 불필요한 에러 무시
ignoreErrors: [
// 브라우저 확장 프로그램 에러
'top.GLOBALS',
// 타사 스크립트 에러
/^Script error\.?$/,
// 개발 전용 에러
'ResizeObserver loop limit exceeded',
],
// 3. URL 기반 필터링
beforeSend(event) {
// 관리자 페이지 에러만 전송
if (!event.request?.url?.includes('/admin/')) {
return null;
}
return event;
}더 알아보기
공식 문서:
심화 주제:
통합 가이드:
요약
Sentry는 프로덕션 환경의 에러와 성능 문제를 실시간으로 추적하는 필수 도구입니다.
핵심 가치:
- 🔍 사용자가 겪는 문제를 실시간으로 파악
- 🎯 에러의 근본 원인을 빠르게 분석
- 📊 릴리스별 품질을 데이터로 측정
- 🚀 성능 병목을 자동으로 감지
시작 방법:
- 5분 안에 설치 및 설정 가능
- 자동 에러 캡처로 즉시 효과 확인
- 점진적으로 성능 모니터링, 알림 등 고급 기능 추가
프로덕션에 배포하는 모든 프로젝트에 Sentry를 적용하여, 사용자 경험을 개선하고 빠르게 문제를 해결하세요.