Skip to content

✍️ 필사 모드: 프런트엔드 모니터링·에러 트래킹 2025 — Sentry·Datadog RUM·PostHog·LogRocket·Session Replay·Source Map·AI 이상탐지 완전 가이드

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

프롤로그 — "내 PC에선 잘 되는데?"

배포를 마치고 모두가 퇴근한 일요일 밤 10시. Slack에 "장바구니 결제가 안 돼요"라는 문의가 들어오기 시작한다. 로컬에서는 잘 되고, 스테이징에서도 멀쩡한데, 프로덕션에서만 에러가 터진다. 어떤 브라우저? 어떤 OS? 어떤 네트워크? 어떤 A/B 변형? 로그가 없다. 아무것도 모른다.

2025년의 프런트엔드 엔지니어에게 모니터링 없는 배포는 눈 감고 운전하는 것과 같다. 백엔드는 20년 전부터 APM·로그·메트릭 삼박자가 기본이었지만, 프런트엔드는 최근 5년 사이에야 실사용자 세계의 가시성이 확보되기 시작했다.

2025년의 주요 변화:

  1. RUM(Real User Monitoring)의 대중화 — Sentry·Datadog·Vercel Speed Insights·PostHog가 무료 또는 저렴한 요금제로 RUM을 제공하면서, 스타트업도 Google CrUX 데이터를 넘어선 세밀한 사용자 행태를 본다.
  2. Session Replay의 윤리 논쟁 — LogRocket·Microsoft Clarity·PostHog로 유저의 화면을 "녹화"하는 기능이 대중화되었지만, 개인정보 유출 사고가 연이어 터지며 "언제·무엇을·얼마나 녹화하느냐"의 가이드라인이 업계 표준화되었다.
  3. AI 기반 이상 탐지 — 단순 threshold 알림을 넘어, 에러 그룹핑·근본 원인 분석·알림 노이즈 감소에 LLM이 투입된다.
  4. 개인정보 보호법 강화 — GDPR(EU)·CCPA(캘리포니아)·한국 개인정보보호법이 프런트엔드 로깅의 범위와 보관 기간을 직접 규제한다.

이번 글에서는 프런트엔드 모니터링의 모든 레이어를 13개 챕터로 풀어본다.


1장 · 무엇을 모니터링할까 — 프런트엔드 관측 가능성의 4축

백엔드 관측 가능성은 보통 Logs · Metrics · Traces 삼각구도로 설명된다. 프런트엔드에는 사용자 자체가 더해져 4축이 된다.

질문도구
Errors무엇이 깨졌는가?Sentry, Bugsnag, Rollbar
Performance (RUM)얼마나 느린가?Datadog RUM, Vercel Speed Insights, SpeedCurve
User Behavior사용자가 무엇을 하는가?PostHog, Mixpanel, Amplitude, Heap
Session Replay사용자가 어떻게 겪었는가?LogRocket, Clarity, PostHog, FullStory

중요한 건 "하나의 도구로 통일해야 한다"는 강박이 틀렸다는 것. Sentry(에러) + PostHog(행태+replay) + Vercel Speed Insights(RUM) 조합이 2025년 스타트업의 사실상 표준.

서로 다른 "이벤트"를 합치면 맥락이 살아난다

  • 이 에러는 어떤 기능에서 나왔나? (PostHog event + Sentry breadcrumb)
  • 느려진 LCP의 원인은 이 빌드인가? (RUM + Release tracking)
  • 이 사용자는 무엇을 시도하다 포기했나? (Session Replay + 클릭 이벤트)

연결되지 않은 도구는 데이터의 노이즈만 늘린다. distinctId·user_id·release를 세 도구에 일관되게 주입하는 것이 가장 중요한 기초 작업.


2장 · Sentry — 에러 트래킹의 표준

2008년 창업한 Sentry는 2025년 시점 오픈소스 에러 트래킹의 de facto 표준. 스택 트레이스, 소스맵, 릴리스 추적, Performance Monitoring, Session Replay, Tracing까지 전방위로 확장되었다.

설치 (Next.js 예시)

npx @sentry/wizard@latest -i nextjs

위 위저드가 다음을 자동 생성한다:

  • sentry.client.config.ts, sentry.server.config.ts, sentry.edge.config.ts
  • next.config.jswithSentryConfig 래핑
  • 샘플 에러 페이지
  • .sentryclirc

최소 설정

// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  environment: process.env.NEXT_PUBLIC_ENV,
  release: process.env.NEXT_PUBLIC_BUILD_ID,
  tracesSampleRate: 0.1,
  replaysSessionSampleRate: 0.05,
  replaysOnErrorSampleRate: 1.0,
  integrations: [
    Sentry.replayIntegration({
      maskAllText: true,
      blockAllMedia: true,
    }),
  ],
});

사용자 컨텍스트 주입

Sentry.setUser({
  id: user.id,
  email: user.email, // 개인정보 주의
  segment: user.plan,
});

Sentry.setTag("feature_flag_checkout_v2", "enabled");
Sentry.setContext("cart", {
  itemCount: cart.items.length,
  total: cart.total,
});

Sentry는 클릭·라우팅·네트워크 요청을 자동으로 breadcrumb으로 기록. 에러 발생 시 "직전에 뭘 눌렀는가"가 드러난다.

Sentry.addBreadcrumb({
  category: "purchase",
  message: "쿠폰 적용 시도",
  level: "info",
  data: { couponCode: "SUMMER" },
});

배포와 연결 — Release Tracking

sentry-cli releases new $VERSION
sentry-cli releases set-commits $VERSION --auto
sentry-cli releases finalize $VERSION

커밋과 릴리스를 연결하면 "이 에러를 유발한 커밋은 이것"이라고 Sentry가 자동 추정해준다.


3장 · Source Map — 압축된 JS의 해독 키

프로덕션 번들은 minify·tree shake·transpile을 거쳐 t.default.map같은 글자만 남는다. Source Map은 이를 원본 코드로 되돌려주는 지도.

원리

빌드 도구(esbuild·Webpack·Turbopack·Vite)가 번들과 함께 .map 파일을 생성한다. 파일 끝에:

//# sourceMappingURL=main.a3f2.js.map

브라우저 DevTools는 이 힌트를 보고 .map을 내려받아 원본 위치로 변환한다.

프로덕션에 .map 업로드 vs 번들 포함

문제: .map을 그대로 CDN에 배포하면 원본 소스가 외부에 공개된다. 민감한 비즈니스 로직·API 비밀이 노출될 수 있다.

해결:

  1. .map 파일을 빌드에는 생성하지만, CDN에 올리지 않고 Sentry에만 업로드
  2. 번들에 sourceMappingURL을 제거하거나 내부 경로로만 지정
  3. Sentry가 에러 접수 시 자신이 보관한 .map으로 스택 트레이스 복원
# Sentry에 source map 업로드
sentry-cli sourcemaps upload \
  --release $VERSION \
  --url-prefix '~/_next' \
  .next/static

Next.js 15의 경우 sentry.config.jswidenClientFileUpload: truehideSourceMaps: true를 조합.

디버깅 효과

  • Before: TypeError: n is undefined at t.default (main.a3f2.js:1:4829)
  • After: TypeError: user is undefined at CheckoutForm.tsx:42:16

소스맵이 없으면 프로덕션 에러는 고대 상형문자다.


4장 · Datadog RUM — 엔터프라이즈 풀스택 옵저버빌리티

Datadog은 백엔드 APM에서 시작해 Frontend RUM·Logs·Synthetics·CI Visibility까지 확장된 통합 플랫폼. 대형 조직에서 백엔드 트레이스와 프런트엔드 세션을 하나의 타임라인으로 보는 능력이 강점.

초기화

import { datadogRum } from "@datadog/browser-rum";

datadogRum.init({
  applicationId: process.env.NEXT_PUBLIC_DD_APP_ID,
  clientToken: process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN,
  site: "datadoghq.com",
  service: "web-app",
  env: "prod",
  version: process.env.NEXT_PUBLIC_BUILD_ID,
  sessionSampleRate: 100,
  sessionReplaySampleRate: 20,
  trackUserInteractions: true,
  trackResources: true,
  trackLongTasks: true,
  defaultPrivacyLevel: "mask-user-input",
});

datadogRum.startSessionReplayRecording();

강점

  • Trace → Session 연결: 백엔드 trace ID를 프런트엔드 요청 헤더에 자동 주입, Datadog UI에서 "이 API 호출은 이 세션에서 발생"을 즉시 탐색
  • Long Task 감지: requestIdleCallback이 blocked된 원인을 자동 수집 (INP 근본 원인 추적)
  • Custom Actions + Vital: 비즈니스 지표(예: "장바구니 담기 버튼 누른 후 1초 내 응답") 정의 가능

비용 주의

Datadog의 RUM 세션 가격은 업계에서 비싼 편. 대규모 트래픽 서비스는 sessionSampleRate를 10%~30%로 조절해야 한다.


5장 · PostHog — 이벤트·RUM·Replay·FlagsOps 통합

PostHog는 오픈소스 Product Analytics + Session Replay + Feature Flag + A/B Test + Experiment를 통합한 "Amplitude + LogRocket + LaunchDarkly 올인원". 2024~2025년에 스타트업 사이에서 급성장한 플랫폼.

초기화

import posthog from "posthog-js";

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: "https://app.posthog.com",
  session_recording: {
    maskAllInputs: true,
    maskTextSelector: "[data-private]",
  },
  autocapture: true,
});

이벤트 추적

posthog.capture("checkout_started", {
  cart_total: cart.total,
  items: cart.items.length,
  coupon_applied: !!coupon,
});

posthog.identify(user.id, {
  email: user.email,
  plan: user.plan,
});

posthog.group("company", company.id, {
  name: company.name,
  industry: company.industry,
});

Feature Flag 연동

if (posthog.isFeatureEnabled("checkout-v2")) {
  return <CheckoutV2 />;
}

2025 업데이트

  • SQL Insights: SQL로 이벤트·세션을 쿼리 (ClickHouse 기반)
  • LLM Observability: OpenAI·Anthropic 호출을 자동 계측
  • Data Warehouse: Snowflake·BigQuery와 양방향 동기

장점: 하나의 도구로 4-5개 카테고리 커버. 단점: Session Replay 품질은 LogRocket·FullStory보다 다소 떨어진다는 평가.


6장 · LogRocket·Clarity·FullStory — Session Replay 전문

LogRocket

  • JS 에러·네트워크·Redux·콘솔·비디오를 통합 녹화
  • 1분 30초 이상 세션 분석이 강점
  • 월 10,000 세션 무료 → 그 이상은 급등

Microsoft Clarity

  • 무료·무제한. 히트맵·Scrollmap·Rage Click·Dead Click 감지
  • Microsoft가 AI·서비스 개선용 데이터로 사용한다는 데이터 제공 조건 동의
  • 개인 블로그·중소 서비스에 압도적 가성비

FullStory

  • 엔터프라이즈 급. 프라이버시 컨트롤과 GDPR 대응이 업계 최고 수준
  • 가격도 엔터프라이즈 급

Session Replay의 가치

  1. 재현 불가 버그 해결: "왜 이 모달이 안 열려요?" → 실제 화면으로 확인
  2. UX 인사이트: 사용자가 어디에서 Rage Click하고, 어디서 이탈하는지
  3. Funnel 분석 보완: 숫자가 말하지 않는 "왜 포기했는지"

7장 · Session Replay의 윤리 — Privacy by Design

2024년의 교훈

2024년 여러 대형 서비스가 Session Replay에 비밀번호·신용카드 번호·주민번호가 녹화된 상태로 저장된 것이 발견되어 GDPR 위반으로 과징금을 맞았다.

방어선 3층

1층: Mask 설정 기본값을 "안전한 쪽"으로

// LogRocket
LogRocket.init("your-app-id", {
  dom: {
    textSanitizer: true,  // 텍스트 기본 마스킹
    inputSanitizer: true, // 입력 기본 마스킹
  },
});

// Sentry Replay
Sentry.replayIntegration({
  maskAllText: true,      // 모든 텍스트 마스킹
  maskAllInputs: true,    // 모든 입력 마스킹
  blockAllMedia: true,    // 이미지·비디오 차단
});

2층: 개인정보 필드에 data-private 또는 data-sensitive 마크업

<input type="password" data-private />
<div data-private>{creditCard}</div>
<span class="ph-no-capture">주민등록번호</span>

3층: 전송 전 클라이언트 측 sanitize

posthog.capture("form_submit", {
  email: user.email.replace(/(.{2}).+(@.+)/, "$1***$2"), // 이메일 부분 마스킹
  // 전화번호·주소는 아예 전송 안 함
});

법적 요구 (GDPR Art. 6, 7)

  • 명시적 동의: 쿠키 배너에서 "세션 녹화"를 별도 항목으로
  • 목적 제한: UX 개선 목적 이외로 활용 금지
  • 보관 기간: 30-90일 권장
  • DSAR (Data Subject Access Request): 사용자가 자신의 녹화 삭제 요청 가능해야 함

8장 · 프런트엔드에서 발생하는 에러의 유형

1. JavaScript Runtime Errors

  • TypeError: Cannot read property 'x' of undefined
  • ReferenceError: foo is not defined
  • 대응: TypeScript + strict null check + 가드 클로저

2. Unhandled Promise Rejections

  • 비동기 함수에서 .catch 누락
  • 대응: 글로벌 핸들러
window.addEventListener("unhandledrejection", (event) => {
  Sentry.captureException(event.reason);
});

3. Chunk Load Error — 배포 시 대표 버그

ChunkLoadError: Loading chunk 42 failed.

원인: 사용자가 페이지를 열어둔 사이 새 배포가 나가 이전 해시의 청크가 CDN에서 사라짐.

해결:

// Next.js — 자동 재시도
// next.config.js
module.exports = {
  experimental: { optimizePackageImports: [...] },
};

// 커스텀 재시도 + 강제 새로고침
window.addEventListener("error", (e) => {
  if (e.message.includes("ChunkLoadError") || e.message.includes("Loading chunk")) {
    window.location.reload();
  }
});

또는 Long-term caching + hash invalidation을 잘 관리한 CDN 전략.

4. Hydration Mismatch

Text content does not match server-rendered HTML.

원인: SSR과 Client에서 다른 값 렌더 (Date, Math.random, localStorage 등).

해결:

// Bad
<div>{new Date().toLocaleString()}</div>

// Good — Client에서만
const [now, setNow] = useState<string>("");
useEffect(() => {
  setNow(new Date().toLocaleString());
}, []);
return <div suppressHydrationWarning>{now}</div>;

5. CORS·CSP 에러

  • Mixed content, strict CSP로 인라인 스크립트 차단
  • 대응: CSP nonce, Report-Only 모드로 점진 도입

6. 3rd-party Script Errors

  • "Script error." (스택 없음)
  • 원인: Cross-origin 스크립트의 보안 제약
  • 대응: <script crossorigin="anonymous"> + CORS 헤더 + Sentry.ignoreErrors

9장 · Core Web Vitals와 연결 — RUM 집계

web-vitals 라이브러리

import { onCLS, onINP, onLCP, onFCP, onTTFB } from "web-vitals";

function sendToAnalytics(metric) {
  navigator.sendBeacon(
    "/api/vitals",
    JSON.stringify({
      name: metric.name,
      value: metric.value,
      id: metric.id,
      rating: metric.rating,
      delta: metric.delta,
      navigationType: metric.navigationType,
    })
  );
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);

Vercel Speed Insights

Next.js + Vercel 조합이면 <SpeedInsights /> 한 줄 추가로 자동 수집. CrUX 기반 RUM을 무료 한도 내에서 즉시 활용.

Custom Dashboard로 집계

  • Percentile 집계: 평균보다는 P75·P90·P95가 의미 있다
  • Segmentation: 기기별(모바일·데스크탑)·라우트별·버전별·지역별로 나눠 본다
  • Regression Detection: 배포 전후 비교로 성능 회귀 자동 감지

10장 · 알림·Alert Fatigue — 노이즈 줄이는 설계

Alert Fatigue의 함정

  • 하루 50건의 Slack 알림이 들어오면 → 아무도 안 본다
  • 중요한 알림이 사소한 알림에 묻힌다
  • 팀의 번아웃과 이직으로 이어짐

SLO 기반 알림 (Google SRE 방식)

"에러가 1개 발생했다"는 노이즈. "에러 예산을 이 속도로 소진하면 월말 SLO를 깬다"가 의미 있는 알림.

slo:
  name: "checkout-success-rate"
  target: 99.9%  # 월 SLO
  window: 30d
  alert:
    - burn_rate: 14.4   # 2% 에러 예산을 1시간 내 소진
      duration: 5m
      severity: critical
    - burn_rate: 6      # 5% 예산을 6시간 내 소진
      duration: 30m
      severity: warning

알림 그룹핑

  • Sentry의 자동 Issue Grouping: 동일 스택 트레이스 패턴을 하나의 Issue로
  • 변화 감지 알림: "새로운 에러 유형이 등장했을 때만 알림"
  • 용량 알림: "에러 발생량이 P95 대비 3배 이상 증가"

Alert 우선순위

  1. Critical — 즉시 대응 필요 (페이지 다운, 결제 실패 급증)
  2. Warning — 업무 시간 내 대응 (일부 기능 이슈, 성능 저하)
  3. Info — 알림 없이 대시보드에만 (트렌드 관찰)

11장 · AI 기반 이상 탐지와 근본 원인 분석

전통적 이상 탐지의 한계

  • Threshold: "에러가 100건 넘으면 알림" → 계절성·트렌드 못 봄
  • Static baseline: 매주 월요일 트래픽 스파이크를 이상으로 감지

2025년의 AI 기반 이상 탐지

Datadog Watchdog, Sentry Insights, PostHog AI, Dynatrace Davis AI 모두 2024~2025년에 LLM·시계열 모델 기반 기능을 출시.

주요 기능:

  1. 자동 이상치 감지: 시계열의 변곡점을 찾아 "지난주 같은 시간대 대비 3.5σ 초과" 식으로 알림
  2. 근본 원인 추정(RCA): 에러 스파이크와 동시에 발생한 변경사항(배포·피처 플래그·외부 의존성)을 자동 연결
  3. 에러 요약: LLM이 스택 트레이스와 로그를 읽어 "어떤 기능의 어떤 유저 흐름에서 실패했다"를 자연어로 요약
  4. 우선순위 랭킹: 비즈니스 영향도(트래픽 × 결제 페이지) 기반으로 자동 랭킹

주의 — AI가 틀릴 수 있다

  • Correlation ≠ Causation: "이 배포 시점에 에러가 증가했다"가 반드시 "이 배포가 원인"은 아니다
  • 최종 판단은 사람이 내려야 한다. AI는 탐색 범위를 좁히는 조수.

12장 · 사용자 피드백 루프 — 숫자와 목소리를 잇기

정량(quantitative)과 정성(qualitative)의 결합

숫자(Sentry, RUM, Analytics)만 보면 **"왜"**가 빠진다. 피드백(NPS, 설문, 지원 티켓)만 보면 **"얼마나"**가 빠진다.

피드백 도구

  • NPS·CSAT: Delighted, Wootric, Typeform
  • 인앱 피드백: Canny, UserVoice, Feedback Fish
  • 세션 녹화 + 코멘트: LogRocket·PostHog에서 사용자가 "이 화면 녹화 공유" 가능
  • Copy linking: 에러 발생 시 "이 문제를 신고하기" 버튼 — Sentry에 User Feedback으로 자동 전송

User Feedback in Sentry

Sentry.showReportDialog({
  user: {
    email: user.email,
    name: user.name,
  },
  title: "문제가 발생했습니다",
  subtitle: "아래 양식을 작성해 주시면 빠르게 해결하겠습니다",
});

사용자 설명이 스택 트레이스와 묶여 이슈에 첨부된다.


13장 · 체크리스트·안티패턴·다음 글 예고

프런트엔드 모니터링 체크리스트 (14개)

  1. Sentry(또는 Bugsnag/Rollbar)로 에러 수집
  2. Source Map을 Sentry에 업로드, 프로덕션에는 공개하지 않음
  3. Release tracking — 커밋·빌드·에러 연결
  4. User context 주입 (id·plan·기능 플래그)
  5. RUM(Vercel Speed Insights·Datadog·PostHog) 배포
  6. Core Web Vitals 수집 + 배포 전후 비교
  7. Session Replay — 기본 mask + data-private 전략
  8. Chunk Load Error 자동 재시도 로직
  9. Hydration Mismatch 모니터링 및 재현 테스트
  10. unhandledrejection 글로벌 핸들러
  11. SLO 기반 알림 — Burn rate alerting
  12. Alert 우선순위 3단계 분리
  13. GDPR·개인정보보호법 대응 (동의·보관 기간·DSAR)
  14. Dashboard — 기기·라우트·버전별 세그먼트 분석

모니터링 안티패턴 TOP 10

  1. console.error만으로 "로그 완료" — 서버로 안 가면 없는 것
  2. Sentry에 PII 평문 전송 — 이메일·전화번호 마스킹 없이 로깅
  3. Source Map을 CDN에 공개 — 원본 노출 + 영업 비밀 유출
  4. 모든 에러를 Critical 알림 — Alert fatigue
  5. Dev·Staging·Prod 이벤트 섞임 — environment 태그 누락
  6. Sample rate 100% — 비용 폭발
  7. data-private 없이 Session Replay — 법적 리스크
  8. Release 추적 없음 — "이 에러 언제부터?" 대답 불가
  9. Hydration Mismatch 방치 — 경고만 수천 건
  10. 사용자 피드백과 에러를 분리 보관 — 정량·정성 단절

다음 글 예고 — Season 6 Ep 9: "프런트엔드 보안"

모니터링·성능·a11y·i18n을 다 갖췄다면 다음은 보안. Ep 9는 프런트엔드 보안.

  • XSS·CSRF·Clickjacking 2025 최신 공격 양상
  • CSP(Content Security Policy)와 nonce·hash·strict-dynamic
  • Trusted Types와 DOM-based XSS 방지
  • 쿠키·JWT·세션 관리 (SameSite, HttpOnly, Secure)
  • OAuth·OIDC·PKCE·Passkey 실전
  • Supply Chain Attack (npm 패키지 위험)
  • SRI(Subresource Integrity)·CSP Report-Only
  • Web Bot Auth·CAPTCHA 대안
  • 한국 전자정부법·ISMS-P·PCI DSS·SOC 2
  • CVE 대응 파이프라인

"보안은 나중에 붙이는 게 아니다. 처음부터 스며들어 있어야 한다."

다음 글에서 만나자.


"모니터링은 배포 이후의 또 다른 제품이다. 에러·성능·행태·감정을 모두 계측하되, 사용자의 프라이버시를 침범하지 않는 설계가 2025년의 품질이다."

현재 단락 (1/309)

배포를 마치고 모두가 퇴근한 일요일 밤 10시. Slack에 "장바구니 결제가 안 돼요"라는 문의가 들어오기 시작한다. 로컬에서는 잘 되고, 스테이징에서도 멀쩡한데, 프로덕션에서만...

작성 글자: 0원문 글자: 11,571작성 단락: 0/309