development

장애 조기 감지를 위한 로그 분석 및 알림 시스템 구축: Sentry 활용법

실시간 장애 조기 감지를 위해 Sentry를 활용한 로그 분석과 알림 시스템을 설계하고 구현하는 방법을 알아봅니다.

목차 보기
  1. 왜 Sentry인가: 로그 이상의 가치를 주는 이벤트 기반 분석
  2. 전체 아키텍처 개요
  3. 로그 분석 전략: Sentry에서 ‘로그’를 다루는 방법
  4. SDK 설정 예시: 언어별 빠른 가이드
  5. JavaScript/Node.js
  6. Python
  7. Java (Spring Boot)
  8. 릴리즈 추적과 CI/CD 연동
  9. 데이터 보안과 규정 준수
  10. 알림 시스템 설계: Issue Alerts vs Metric Alerts
  11. 1) 에러율 급증 감지(서비스 레벨)
  12. 2) p95 응답시간 이상치 감지(성능)
  13. 3) 릴리즈 회귀(Release Regression)
  14. 4) 사용자 영향 기반(세션/크래시프리)
  15. Slack/PagerDuty 연동과 라우팅 전략
  16. Discover와 대시보드: 분석과 시각화
  17. 노이즈 억제: 샘플링, 필터, 그룹핑
  18. 이슈 오너십과 운영 절차
  19. 보강 지표: SLO와 버른레이트 관점의 경보
  20. 실전 시나리오: 데이터베이스 장애 조기 감지
  21. 운영 팁: 자주 겪는 함정과 해결책
  22. 체크리스트: 바로 적용하기
  23. 마무리

실시간으로 장애를 감지하고 다운타임을 최소화하려면 로그를 체계적으로 수집하고 분석하며, 신뢰할 수 있는 알림 체계를 갖추는 것이 핵심입니다. 이 글에서는 에러 및 퍼포먼스 모니터링에 특화된 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%
  • 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 타임아웃이 발생해 초기에 사용자 불만이 증가하는 상황

  1. SDK 태깅
  • DB 접속 오류 발생 시 tags: { service: "api", db.host: "rds-1", region: "ap-northeast-2" } 추가
  • captureException 호출 시 endpoint, customer_tier도 태그로 기록
  1. 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
  1. 알림 수신과 초기 대응
  • Slack 알림에서 대시보드 링크 클릭 → rds-1에서 집중 발생 확인
  • 성능 대시보드에서 같은 시간대 p95 증가도 확인
  1. 원인 파악
  • Breadcrumbs에 캐시 미스가 증가한 로그 확인
  • 최근 릴리즈에서 커넥션 풀 설정이 변경된 suspect commit 제시됨
  1. 조치
  • 커넥션 풀 설정 롤백
  • DB 호스트별 fingerprint 적용으로 향후 이슈 분리 관리
  1. 사후 조치
  • 캐시 미스 비율에 대한 추가 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/대시보드·알림 규칙을 긴밀히 엮고, 샘플링과 필터로 노이즈를 줄이면, 장애를 “사용자 체감 전에” 포착하고 대응하는 조직 문화를 만들 수 있습니다. 이번 글의 예제와 체크리스트를 바탕으로, 여러분의 서비스에 맞는 조기 감지 전략을 오늘부터 적용해 보세요.

  • #Sentry
  • #로그분석
  • #장애감지
  • #알림시스템
  • #DevOps