실시간으로 장애를 감지하고 다운타임을 최소화하려면 로그를 체계적으로 수집하고 분석하며, 신뢰할 수 있는 알림 체계를 갖추는 것이 핵심입니다. 이 글에서는 에러 및 퍼포먼스 모니터링에 특화된 Sentry를 중심으로, 로그 분석과 알림 시스템을 설계·구현하는 실전 방법을 다룹니다. 단순 통계 이상의 “조기 감지”를 위해 어떤 지표를 선택하고, 어떤 규칙을 만들며, 어떻게 노이즈를 줄이는지까지 구체적으로 안내합니다.
왜 Sentry인가: 로그 이상의 가치를 주는 이벤트 기반 분석
전통적인 로그 수집기는 방대한 텍스트 로그를 수집·검색하는 데 강점이 있지만, 오류의 “맥락(context)”과 “그룹화(grouping)”, “릴리즈 추적(release tracking)”, “성능 추적(tracing)”까지 한 번에 연결하기는 어렵습니다. Sentry는 다음에 강합니다.
- 예외·메시지·성능 트랜잭션을 이벤트로 수집하고 자동 그룹화
- 사용자·릴리즈·환경·서비스 등 태그 기반의 강력한 필터링
- 코드 오너십, 서스펙트 커밋, 릴리즈 회귀(regression) 추적
- Discover/대시보드/알림 규칙(이슈 알림, 메트릭 알림)을 통한 조기 감지
- Slack, PagerDuty 등과 손쉬운 연동
즉, “장애 신호를 조기에 감지하고 누구에게 어떤 메시지로 알릴 것인가”에 집중하기 좋습니다.
전체 아키텍처 개요
- 애플리케이션/마이크로서비스
- Sentry SDK로 예외, 메시지(로그), 성능 트레이스 전송
- 서비스명, 환경(env), 릴리즈, 리전 등 태그 주입
- Sentry 플랫폼(SaaS 또는 Self-hosted)
- 이벤트 집계/그룹화, Discover/대시보드
- 알림 규칙: 이슈 기반, 메트릭 기반
- 통합: Slack, 이메일, PagerDuty, Jira 등
- 운영 흐름
- 알림 → 온콜/오너 자동 라우팅 → 대시보드 확인 → 롤백/핫픽스 → 사후 분석(포스트모템)
이 구조에서 핵심은 “태깅 전략”, “샘플링 및 노이즈 억제”, “알림 규칙 설계”, “릴리즈 파이프라인 연계”입니다.
로그 분석 전략: Sentry에서 ‘로그’를 다루는 방법
Sentry는 전통적 의미의 라인 단위 텍스트 로그 저장소가 아니라, 이벤트 기반입니다. 하지만 다음 방법으로 로그 분석을 충분히 구현할 수 있습니다.
- captureException: 예외와 스택트레이스를 포함한 에러 이벤트
- captureMessage: 특정 메시지를 이벤트화(레벨: info/warning/error 등)
- 로깅 프레임워크 연동: Python logging, Java Logback, Node Winston 등에서 에러 레벨 이상을 이벤트로 전송
- Breadcrumbs: 오류 직전의 로그/네트워크 요청/클릭 등 흐름 기록
- Tags/Contexts: 서비스명(service), 환경(env), 릴리즈, 리전, 고객 티어, 기능 플래그 등으로 풍부한 필터링
- Grouping/Fingerprints: 이벤트를 원인별로 묶어 노이즈 줄이기. 필요한 경우 커스텀 fingerprint로 그룹 분리/합치기
추천 태그(예시):
- service: web, api, worker, batch
- env: production, staging
- region: ap-northeast-2, us-east-1
- release: [email protected]
- endpoint, db.host, feature_flag, customer_tier
이러한 태그는 Discover 쿼리에서 강력한 필터로 작동하고, 경보 라우팅의 기준이 됩니다.
SDK 설정 예시: 언어별 빠른 가이드
JavaScript/Node.js
// npm i @sentry/node @sentry/profiling-node
const Sentry = require("@sentry/node");
const { nodeProfilingIntegration } = require("@sentry/profiling-node");
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || "production",
release: process.env.RELEASE || "[email protected]",
integrations: [
nodeProfilingIntegration(),
// HTTP/Express 자동 계측 등
new Sentry.Integrations.Http({ tracing: true }),
],
tracesSampleRate: 0.2, // 성능 트레이싱 샘플링
sampleRate: 1.0, // 에러 이벤트 샘플링
beforeSend(event) {
// 민감정보 마스킹
if (event.user && event.user.email) {
event.user.email = "[redacted]";
}
if (event.request && event.request.headers) {
delete event.request.headers.Authorization;
}
return event;
},
});
// 예외
try {
// ...
} catch (e) {
Sentry.captureException(e, { tags: { service: "api", region: "ap-northeast-2" } });
}
// 메시지(로그 이벤트)
Sentry.captureMessage("Cache miss on user profile", {
level: "warning",
tags: { service: "web", feature_flag: "new-cache" },
});
Winston 연동(선택):
const winston = require("winston");
const Sentry = require("@sentry/node");
require("winston-transport-sentry-node"); // 별도 패키지
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new (require("winston-transport-sentry-node").default)({
sentry: Sentry,
level: "error",
}),
],
});
Python
# pip install sentry-sdk
import logging
import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.django import DjangoIntegration # 예: Django
# from sentry_sdk.integrations.fastapi import FastApiIntegration # 예: FastAPI
sentry_logging = LoggingIntegration(
level=logging.INFO, # INFO 이상 로깅을 breadcrumbs로
event_level=logging.ERROR, # ERROR 이상은 이벤트 전송
)
sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
environment=os.environ.get("ENV", "production"),
release=os.environ.get("RELEASE", "[email protected]"),
integrations=[sentry_logging, DjangoIntegration()],
traces_sample_rate=0.2,
before_send=lambda event, hint: scrub(event),
)
def scrub(event):
# 민감정보 제거
request = event.get("request", {})
headers = request.get("headers", {})
headers.pop("authorization", None)
user = event.get("user", {})
if "email" in user:
user["email"] = "[redacted]"
return event
# 일반 로깅
logger = logging.getLogger(__name__)
logger.info("user fetched", extra={"user_id": 123})
logger.error("db timeout", extra={"db.host": "rds-cluster-1"}, exc_info=True)
Java (Spring Boot)
// build.gradle
// implementation 'io.sentry:sentry-spring-boot-starter:7.10.0'
// implementation 'io.sentry:sentry-logback:7.10.0'
import io.sentry.Sentry;
import javax.annotation.PostConstruct;
@Configuration
public class SentryConfig {
@PostConstruct
public void init() {
Sentry.init(options -> {
options.setDsn(System.getenv("SENTRY_DSN"));
options.setEnvironment(System.getenv("ENV"));
options.setRelease(System.getenv("RELEASE"));
options.setTracesSampleRate(0.2);
options.setBeforeSend((event, hint) -> {
if (event.getUser() != null) event.getUser().setEmail("[redacted]");
return event;
});
});
}
}
Logback 연동(logback-spring.xml):
<configuration>
<appender name="SENTRY" class="io.sentry.logback.SentryAppender">
<minimumEventLevel>ERROR</minimumEventLevel>
</appender>
<root level="INFO">
<appender-ref ref="SENTRY"/>
</root>
</configuration>
이렇게 하면 애플리케이션 로그의 ERROR 이상은 이벤트로 전송되고, INFO/DEBUG는 breadcrumbs로 남아 장애 분석의 맥락을 제공합니다.
릴리즈 추적과 CI/CD 연동
조기 감지의 핵심은 “이 릴리즈에서 문제가 시작됐는가?”를 빠르게 확인하는 것입니다. Sentry 릴리즈 추적을 CI/CD 파이프라인에 넣어주세요.
- 릴리즈 생성: 커밋/태그 기반
- 소스맵 업로드(프런트엔드/Node)
- 디플로이 마킹(환경별)
- 서스펙트 커밋/오너 자동 추정
예: GitHub Actions에서 sentry-cli 사용
- name: Install Sentry CLI
run: curl -sL https://sentry.io/get-cli/ | bash
- name: Create Sentry Release
run: |
export SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
export SENTRY_ORG=my-org
export SENTRY_PROJECT=my-app
VERSION=app@${{ github.sha }}
sentry-cli releases new $VERSION
sentry-cli releases set-commits --auto $VERSION
sentry-cli releases files $VERSION upload-sourcemaps dist --rewrite
sentry-cli releases finalize $VERSION
sentry-cli releases deploys $VERSION new -e production
애플리케이션 초기화 시 release 값을 동일하게 설정하세요. 이로써 “해당 릴리즈에서 에러 급증” 같은 메트릭 알림을 만들 수 있습니다.
데이터 보안과 규정 준수
운영 로그/이벤트에는 민감정보가 섞이기 쉽습니다. 다음을 반드시 수행하세요.
- Sentry 서버 설정: Data Scrubbing(PII 제거) 규칙 활성화
- 이메일/세션 토큰/Authorization 헤더 제거
- 요청 바디/쿼리 파라미터 키 패턴 기반 마스킹
- SDK 훅: beforeSend에서 추가 필터링
- IP 익명화 옵션 검토
- 보존 기간(retention)과 접근 제어(Role/Team) 정책 정의
- 지역/백업/암호화 요구사항(KISA, PIPA, GDPR 등) 점검
- 정말 필요한 경우에만 Attachment(로그 파일) 업로드
Self-hosted가 필요한 경우 Sentry Relay와 내부망 배치를 통해 데이터 경계를 지키는 방법도 고려합니다.
알림 시스템 설계: Issue Alerts vs Metric Alerts
Sentry 경보는 크게 두 가지입니다.
- Issue Alerts: 새로운 이슈 생성, 회귀(regression), 빈도 증가 등 이슈 중심 조건
- Metric Alerts: Discover 쿼리 기반의 메트릭(에러율, 사용자 수, p95 지연 등) 임계치 탐지
조기 감지에는 Metric Alerts가 특히 유용합니다. 다음과 같이 설계해 보세요.
1) 에러율 급증 감지(서비스 레벨)
- Dataset: Errors
- Aggregate: count() 또는 failure_rate()
- Filter: environment:production AND tags[service]:api
- Threshold:
- Warning: count() > 50 in 5m
- Critical: count() > 200 in 5m
- Actions: Slack #oncall-api, PagerDuty Critical
2) p95 응답시간 이상치 감지(성능)
- Dataset: Transactions
- Aggregate: p95()
- Filter: transaction:/v1/orders/* AND environment:production
- Threshold:
- Warning: p95() > 800ms for 5m
- Critical: p95() > 1200ms for 5m
3) 릴리즈 회귀(Release Regression)
- Issue Alert: “This issue is a regression” AND environment:production
- Action: Notify code owners, Jira 티켓 생성
4) 사용자 영향 기반(세션/크래시프리)
- Dataset: Sessions
- Aggregate: crash_free_rate() or count_unique(user)
- Filter: release:[email protected].* AND platform:ios
- Threshold:
- Critical: crash_free_rate() < 99.5% for 30m
알림 노이즈를 줄이려면 “For at least” 윈도우를 설정하고, Warning과 Critical을 분리해 에스컬레이션 단계를 명확히 합니다.
Slack/PagerDuty 연동과 라우팅 전략
- Slack
- Sentry Organization → Integrations → Slack 설치
- 프로젝트별 채널 매핑(예: web= #oncall-web, api= #oncall-api)
- Critical만 PagerDuty, Warning은 Slack으로 처리
- PagerDuty/Opsgenie
- Metric Alerts의 Critical 트리거 시 인시던트 생성
- 서비스별 라우팅 규칙으로 담당 팀에 직접 전달
- 이메일/모바일 푸시
- 회귀/신규 이슈 등 소음 낮은 이벤트에 사용
팁: 알림 메시지 템플릿에 “대시보드 링크”와 “런북 링크”를 포함해 대응 시간을 단축하세요.
Discover와 대시보드: 분석과 시각화
Discover 쿼리 예시
-
에러 스파이크 원인 파악:
- Query: environment:production event.type:error tags[service]:api
- Columns: count(), issue, exception.type, tags[db.host], release
- Drill-down: 특정 release/host에서 급증했는지 확인
-
엔드포인트별 지연:
- Dataset: Transactions
- Columns: transaction, p50(), p95(), failure_rate()
- Filter: service:web AND region:ap-northeast-2
-
고객 티어별 장애 영향:
- Filter: tags[customer_tier]:enterprise
- Columns: count_unique(user), count()
이 쿼리를 위젯으로 저장해 대시보드를 구성하고, 배포 직후 1~2시간은 해당 대시보드를 집중 모니터링합니다.
노이즈 억제: 샘플링, 필터, 그룹핑
- 샘플링
- Errors:
sampleRate로 일반 에러 이벤트 샘플링 - Performance:
tracesSampleRate또는tracesSampler로 트랜잭션 샘플링 - 트래픽 폭증 시 크리티컬 경로/특정 예외 타입만 100% 샘플링, 나머지는 10~20%
- Errors:
- Inbound Filters
- 공통 노이즈(예: 404, Bot User-Agent) 필터링
- Grouping & Fingerprinting
- 동일 원인의 스택트레이스를 하나의 이슈로 묶어 경보 폭발 방지
- 필요시 fingerprint로 의도적으로 분리(예: db.host별 다른 이슈)
Node에서 동적 샘플링 예시:
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampler: samplingContext => {
const { transactionContext, request } = samplingContext;
if (process.env.NODE_ENV !== "production") return 0.0;
if (transactionContext && transactionContext.name?.startsWith("/internal/health")) return 0.0;
if (request?.headers?.["x-sla-tier"] === "gold") return 1.0;
return 0.2;
},
});
이슈 오너십과 운영 절차
- 코드 오너십
- 저장소의 CODEOWNERS 혹은 Sentry의 Ownership Rules로 파일 경로/태그 기준 오너 지정
- 새 이슈/회귀 시 오너 자동 배정
- Suspect Commits
- 릴리즈 커밋과 연결해 문제를 유발했을 가능성이 높은 커밋을 자동 제시
- 티켓/런북
- Jira/GitHub Issues 자동 생성
- Sentry 이슈 설명 상단에 “런북 URL” 템플릿 포함
- 해제 규칙
- “Resolve in next release”로 릴리즈 단위 해결 추적
- 무해한 노이즈는 Ignore 또는 필터 추가
보강 지표: SLO와 버른레이트 관점의 경보
장애 조기 감지는 SLO 위반을 미연에 방지하는 과정입니다.
- SLO 예: API p95 < 800ms, 에러율 < 1%, 크래시프리율 > 99.5%
- 경보는 “문턱”뿐 아니라 “기울기(상승 속도)”를 반영
- 예: p95가 10분 내 50% 이상 상승 → Warning
- 시간 가중치와 지속 시간
- 일시적 스파이크를 걸러내고, 지속될 때만 알림
Sentry Metric Alerts에서 Warning/Critical의 임계값과 “for at least” 창을 구분해 운영 피로도를 낮추세요.
실전 시나리오: 데이터베이스 장애 조기 감지
가정: API 서비스에서 간헐적인 DB 타임아웃이 발생해 초기에 사용자 불만이 증가하는 상황
- SDK 태깅
- DB 접속 오류 발생 시
tags: { service: "api", db.host: "rds-1", region: "ap-northeast-2" }추가 captureException호출 시 endpoint, customer_tier도 태그로 기록
- Discover로 감지 쿼리 생성
- Dataset: Errors
- Filter: environment:production exception.type:DBTimeoutError tags[service]:api
- Columns: count(), tags[db.host], release
- 이 쿼리로 Metric Alert 생성: count() > 30 in 5m → Slack #oncall-api Warning, > 120 in 5m → PagerDuty Critical
- 알림 수신과 초기 대응
- Slack 알림에서 대시보드 링크 클릭 → rds-1에서 집중 발생 확인
- 성능 대시보드에서 같은 시간대 p95 증가도 확인
- 원인 파악
- Breadcrumbs에 캐시 미스가 증가한 로그 확인
- 최근 릴리즈에서 커넥션 풀 설정이 변경된 suspect commit 제시됨
- 조치
- 커넥션 풀 설정 롤백
- DB 호스트별 fingerprint 적용으로 향후 이슈 분리 관리
- 사후 조치
- 캐시 미스 비율에 대한 추가 Metric Alert 생성
- DB 타임아웃 예외는 100% 샘플링, 기타 에러는 20%로 샘플링 규칙 조정
- 런북 업데이트: “DB 타임아웃 발생 시 체크리스트”
이 흐름으로 “사용자 대량 이탈이 발생하기 전” 신호를 잡아 빠르게 대응할 수 있습니다.
운영 팁: 자주 겪는 함정과 해결책
- 너무 많은 알림: Warning과 Critical을 분리하고, “for at least” 윈도우로 일시 스파이크 억제
- 태그 부족: service/env/release/region/endpoint는 필수. 없으면 라우팅, 대시보드, 분석 모두 약해짐
- 소스맵 미업로드: 프런트엔드 스택트레이스가 난독화되어 원인 파악 지연 → CI에 업로드 자동화
- 민감정보 유출: beforeSend와 Data Scrubbing을 동시에 사용, 보안 리뷰 필수
- 샘플링 과도: 디버깅에 필요한 데이터가 부족 → 크리티컬 경로/예외는 샘플링 1.0 유지
- 대시보드 방치: 릴리즈 후 24시간은 “릴리즈 건강(Release Health)” 위젯 중심 모니터링
체크리스트: 바로 적용하기
- Sentry 프로젝트/환경/팀 구조 설계
- SDK 설치 및 필수 태그(service, env, release, region) 주입
- 로깅 프레임워크 연동: ERROR 이상 이벤트화, INFO/DEBUG는 breadcrumbs
- CI/CD에 release 추적/소스맵 업로드 추가
- Data Scrubbing/PII 필터링 룰 적용 + beforeSend 구현
- 핵심 알림 규칙
- 에러율 급증(서비스별)
- p95 증가(엔드포인트별)
- 릴리즈 회귀
- 고객 티어/세션 기반 임팩트
- Slack/PagerDuty 연동 및 채널/에스컬레이션 정의
- 대시보드: 에러, 성능, 릴리즈 건강 위젯 구성
- 샘플링/필터/그룹핑으로 노이즈 억제
- 오너십 규칙, 런북, 티켓 연계
마무리
Sentry를 중심으로 로그 분석과 알림 시스템을 설계하면, 단순한 “에러 발생 알림”을 넘어 “맥락이 있는 조기 감지 체계”를 구축할 수 있습니다. 태깅·릴리즈 추적·Discover/대시보드·알림 규칙을 긴밀히 엮고, 샘플링과 필터로 노이즈를 줄이면, 장애를 “사용자 체감 전에” 포착하고 대응하는 조직 문화를 만들 수 있습니다. 이번 글의 예제와 체크리스트를 바탕으로, 여러분의 서비스에 맞는 조기 감지 전략을 오늘부터 적용해 보세요.