이미지 로딩 중...

Next.js 실전 운영 7편 - 실시간 모니터링과 에러 추적 - 슬라이드 1/11
A

AI Generated

2025. 11. 8. · 3 Views

Next.js 실전 운영 7편 - 실시간 모니터링과 에러 추적

프로덕션 환경에서 Next.js 애플리케이션을 안정적으로 운영하기 위한 실시간 모니터링과 에러 추적 시스템 구축 가이드입니다. Sentry, LogRocket, Vercel Analytics 등 실무 필수 도구를 활용하여 사용자 경험을 개선하고 장애를 빠르게 대응하는 방법을 배웁니다.


목차

  1. Sentry로 에러 추적하기 - 프로덕션 에러를 실시간으로 캐치
  2. 서버 사이드 에러 모니터링 - API Route와 SSR 에러 추적
  3. Vercel Analytics로 성능 모니터링 - Core Web Vitals 추적
  4. LogRocket으로 세션 리플레이 - 사용자 화면 녹화와 디버깅
  5. 커스텀 메트릭으로 비즈니스 지표 추적 - 전환율과 사용자 행동 분석
  6. 알림과 온콜 시스템 구축 - 장애 발생 시 즉시 대응
  7. Health Check와 Uptime 모니터링 - 서비스 가용성 추적
  8. 로그 집계와 검색 - 프로덕션 로그를 효율적으로 관리
  9. 배포 추적과 Release Health - 배포가 서비스에 미치는 영향 분석
  10. 성능 프로파일링과 병목 지점 찾기 - 느린 코드 최적화

1. Sentry로 에러 추적하기 - 프로덕션 에러를 실시간으로 캐치

시작하며

여러분이 프로덕션에 배포한 Next.js 앱에서 사용자가 "빈 화면"을 보고 있다는 제보를 받은 적 있나요? 로컬에서는 멀쩡하게 작동하던 코드가 프로덕션에서만 에러가 발생하고, 정확히 어디서 문제가 생겼는지 찾기 어려운 상황 말이죠.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 사용자의 브라우저 환경, 네트워크 상태, 데이터 상태에 따라 예상치 못한 에러가 발생하는데, 콘솔 로그만으로는 이를 추적하기 어렵습니다.

더 큰 문제는 사용자가 직접 제보하기 전까지는 에러의 존재조차 모를 수 있다는 점입니다. 바로 이럴 때 필요한 것이 Sentry입니다.

Sentry는 프로덕션 환경에서 발생하는 모든 에러를 자동으로 수집하고, 에러가 발생한 환경, 스택 트레이스, 사용자 정보까지 상세하게 기록해줍니다.

개요

간단히 말해서, Sentry는 애플리케이션에서 발생하는 에러를 실시간으로 감지하고 추적하는 에러 모니터링 플랫폼입니다. 왜 이 도구가 필요한지 실무 관점에서 설명하면, 프로덕션 환경에서는 수천 명의 사용자가 동시에 접속하고 각기 다른 환경에서 앱을 사용합니다.

특정 브라우저에서만 발생하는 에러, 특정 API 응답에서만 발생하는 에러 등을 일일이 재현하고 찾아내기는 거의 불가능합니다. 예를 들어, Safari에서만 발생하는 날짜 파싱 에러나 느린 네트워크에서만 발생하는 타임아웃 에러 같은 경우에 Sentry가 매우 유용합니다.

기존에는 try-catch로 에러를 잡아서 console.log를 찍거나 서버에 수동으로 로그를 전송했다면, 이제는 Sentry가 자동으로 모든 에러를 캐치하고 대시보드에 표시해줍니다. 심지어 에러가 발생한 순간의 사용자 액션, 네트워크 요청, 브라우저 정보까지 함께 기록됩니다.

Sentry의 핵심 특징은 첫째, 자동 에러 캡처로 코드 수정 없이도 대부분의 에러를 잡아냅니다. 둘째, Source Map을 통해 minify된 프로덕션 코드를 원본 코드로 변환하여 정확한 에러 위치를 알려줍니다.

셋째, Release Tracking으로 어느 배포 버전에서 에러가 발생했는지 추적할 수 있습니다. 이러한 특징들이 빠른 장애 대응과 안정적인 서비스 운영에 필수적입니다.

코드 예제

// sentry.client.config.ts - 클라이언트 사이드 Sentry 설정
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

  // 배포 환경에 따라 샘플링 비율 조정
  tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,

  // 현재 배포 버전 추적
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,

  // 환경 설정
  environment: process.env.NEXT_PUBLIC_VERCEL_ENV || "development",

  // 민감한 정보 필터링
  beforeSend(event) {
    // 로컬 개발 환경에서는 에러 전송 안 함
    if (event.request?.url?.includes("localhost")) return null;
    return event;
  },

  // 에러 발생 시 사용자 피드백 수집
  integrations: [new Sentry.BrowserTracing()],
});

설명

이것이 하는 일: Sentry SDK를 Next.js 앱에 초기화하여 클라이언트 사이드에서 발생하는 모든 에러를 자동으로 캡처하고 Sentry 서버로 전송합니다. 첫 번째로, Sentry.init() 함수가 실행되면서 DSN(Data Source Name)을 통해 여러분의 Sentry 프로젝트와 연결됩니다.

이때 tracesSampleRate를 0.1로 설정한 것은 프로덕션에서 모든 트랜잭션의 10%만 추적하여 비용을 절감하면서도 충분한 데이터를 수집하기 위함입니다. 개발 환경에서는 1.0으로 설정하여 모든 에러를 확인할 수 있습니다.

그 다음으로, releaseenvironment 설정이 실행되면서 현재 배포 버전과 환경 정보가 기록됩니다. Vercel을 사용한다면 Git 커밋 SHA를 release 버전으로 사용하여, 특정 커밋에서 발생한 에러를 정확히 추적할 수 있습니다.

이는 "이번 배포 후 갑자기 에러가 증가했다"는 상황을 빠르게 파악하는 데 필수적입니다. beforeSend 훅은 에러가 전송되기 직전에 실행되어 민감한 정보를 필터링하거나 불필요한 에러를 제외할 수 있습니다.

예를 들어 로컬 개발 환경의 에러는 전송하지 않도록 설정했습니다. 또한 사용자의 비밀번호, 토큰 같은 민감한 정보가 에러 컨텍스트에 포함되지 않도록 추가 필터링도 가능합니다.

BrowserTracing 인테그레이션은 사용자의 페이지 네비게이션, 클릭 이벤트, 네트워크 요청 등을 자동으로 추적합니다. 에러가 발생했을 때 "사용자가 어떤 페이지에서 어떤 버튼을 클릭했고, 어떤 API를 호출했는지" 전체 맥락을 파악할 수 있어 재현이 어려운 에러도 쉽게 디버깅할 수 있습니다.

여러분이 이 코드를 사용하면 프로덕션에서 발생하는 모든 JavaScript 에러, 네트워크 에러, React 에러 바운더리 에러가 자동으로 Sentry 대시보드에 표시됩니다. 에러가 발생한 브라우저, OS, 사용자 정보, 에러 발생 빈도까지 한눈에 파악할 수 있어 우선순위를 정하여 중요한 에러부터 해결할 수 있습니다.

실전 팁

💡 Source Map 업로드는 필수입니다. next.config.js에서 sentry-webpack-plugin을 설정하여 빌드 시 자동으로 Source Map을 업로드하세요. 그래야 minify된 코드가 아닌 원본 코드 라인을 정확히 볼 수 있습니다.

💡 에러 알림을 Slack이나 Discord와 연동하세요. 심각한 에러가 발생하면 즉시 팀에 알림이 가도록 설정하면 장애 대응 시간을 크게 줄일 수 있습니다. Alert 규칙에서 "10분 내 동일 에러 10회 이상" 같은 조건을 설정하세요.

💡 사용자 컨텍스트를 추가하세요. Sentry.setUser({ id: user.id, email: user.email })로 로그인한 사용자 정보를 추가하면, 특정 사용자에게만 발생하는 에러를 빠르게 찾을 수 있습니다. 단, GDPR을 고려하여 민감한 정보는 제외하세요.

💡 Performance Monitoring도 함께 활용하세요. tracesSampleRate를 설정하면 에러뿐만 아니라 느린 페이지, 느린 API 호출도 추적할 수 있습니다. "에러는 없지만 사용자가 느리다고 불평하는" 상황을 해결하는 데 유용합니다.

💡 에러를 그룹화하고 무시 설정을 활용하세요. 브라우저 익스텐션이나 광고 차단기로 인한 에러는 무시 리스트에 추가하여 노이즈를 줄이세요. Sentry 대시보드에서 에러 패턴을 보고 merge 하거나 ignore 처리할 수 있습니다.


2. 서버 사이드 에러 모니터링 - API Route와 SSR 에러 추적

시작하며

여러분의 Next.js 앱에서 API Route가 간헐적으로 500 에러를 반환하는데, 로그를 확인해도 정확한 원인을 찾기 어려운 경험 있으신가요? 특히 데이터베이스 연결 오류, 외부 API 타임아웃, 예상치 못한 null 값 같은 문제들은 특정 상황에서만 발생해서 재현하기도 어렵습니다.

클라이언트 에러만큼 서버 사이드 에러도 중요합니다. 서버 에러는 직접적으로 사용자에게 영향을 미치고, 데이터 손실이나 보안 문제로 이어질 수 있습니다.

하지만 서버 로그는 방대하고, 여러 인스턴스에 분산되어 있어서 특정 에러를 찾기 어렵습니다. 바로 이럴 때 필요한 것이 서버 사이드 Sentry 설정입니다.

Next.js의 API Route, getServerSideProps, Middleware에서 발생하는 모든 에러를 자동으로 캡처하여 클라이언트 에러와 동일한 대시보드에서 관리할 수 있습니다.

개요

간단히 말해서, 서버 사이드 Sentry는 Node.js 환경에서 실행되는 Next.js 서버 코드의 에러를 추적하는 시스템입니다. 왜 서버 사이드 모니터링이 필요한지 설명하면, API Route는 데이터베이스, 외부 API, 파일 시스템 등 다양한 리소스와 상호작용하면서 예상치 못한 에러가 발생할 수 있습니다.

예를 들어, 데이터베이스 커넥션 풀이 고갈되어 발생하는 에러나, 외부 결제 API의 갑작스러운 응답 형식 변경으로 인한 파싱 에러 같은 경우에 서버 모니터링이 매우 유용합니다. 기존에는 서버 로그를 CloudWatch나 파일로 남기고 일일이 검색했다면, 이제는 Sentry가 에러를 자동으로 분류하고 심각도별로 정리해줍니다.

같은 에러가 여러 번 발생하면 자동으로 그룹화하여 중복을 제거합니다. 서버 사이드 Sentry의 핵심 특징은 첫째, Request Context를 자동으로 수집하여 요청 헤더, 쿼리 파라미터, 사용자 IP 등을 함께 기록합니다.

둘째, 비동기 에러도 정확히 추적하여 Promise rejection이나 async/await 에러를 놓치지 않습니다. 셋째, Performance Monitoring으로 느린 API 엔드포인트를 식별할 수 있습니다.

이러한 특징들이 서버 안정성을 크게 향상시킵니다.

코드 예제

// sentry.server.config.ts - 서버 사이드 Sentry 설정
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 0.1,

  // 서버 에러는 모두 수집 (비용 고려해서 조정 가능)
  sampleRate: 1.0,

  // 배포 정보
  release: process.env.VERCEL_GIT_COMMIT_SHA,
  environment: process.env.VERCEL_ENV || "development",

  // 서버 컨텍스트 추가
  beforeSend(event, hint) {
    // API 키나 토큰 같은 민감 정보 제거
    if (event.request?.headers) {
      delete event.request.headers['authorization'];
      delete event.request.headers['cookie'];
    }
    return event;
  },
});

설명

이것이 하는 일: Next.js 서버 환경에서 Sentry를 초기화하여 API Route, getServerSideProps, Middleware 등에서 발생하는 모든 에러를 자동으로 캡처하고 추적합니다. 첫 번째로, 서버 환경에서 Sentry.init()이 실행되면서 Node.js 프로세스의 uncaughtException과 unhandledRejection을 자동으로 감지합니다.

sampleRate: 1.0은 서버 에러를 100% 수집한다는 의미로, 클라이언트보다 서버 에러가 더 치명적이기 때문에 모두 수집하는 것이 일반적입니다. 트래픽이 매우 많다면 비용을 고려하여 낮출 수 있습니다.

그 다음으로, beforeSend 훅에서 민감한 정보를 제거합니다. 서버 에러에는 요청 헤더에 포함된 인증 토큰, 쿠키, API 키 등이 포함될 수 있는데, 이를 Sentry로 전송하면 보안 문제가 발생할 수 있습니다.

authorization 헤더와 cookie를 삭제하여 민감한 정보가 로그에 남지 않도록 보호합니다. Sentry는 자동으로 Request Context를 수집하여 에러가 발생한 API 엔드포인트, HTTP 메서드, 쿼리 파라미터, 사용자 IP를 기록합니다.

예를 들어 /api/orders에서 에러가 발생했다면, 어떤 주문 ID로 요청했는지, POST 요청이었는지 GET 요청이었는지 모두 확인할 수 있습니다. 서버 사이드에서는 Stack Trace가 특히 중요합니다.

데이터베이스 쿼리 에러, 파일 시스템 에러, 외부 API 호출 에러 등은 클라이언트에서 볼 수 없는 정보이므로, 정확한 Stack Trace를 통해 어느 파일의 어느 라인에서 에러가 발생했는지 즉시 파악할 수 있습니다. 여러분이 이 설정을 사용하면 API Route에서 발생하는 모든 에러가 Sentry 대시보드에 표시되며, 에러 발생 빈도, 영향받은 사용자 수, 에러 트렌드를 한눈에 볼 수 있습니다.

"갑자기 500 에러가 급증했다"는 것을 실시간으로 알 수 있어 장애를 조기에 발견하고 대응할 수 있습니다.

실전 팁

💡 API Route에서 명시적으로 에러를 캡처하세요. try-catch로 예외를 잡아서 Sentry.captureException(error)를 호출하면 추가 컨텍스트를 함께 전송할 수 있습니다. Sentry.setContext('order', { orderId, userId })로 비즈니스 정보를 추가하면 디버깅이 훨씬 쉬워집니다.

💡 데이터베이스 쿼리 에러는 별도로 분류하세요. Sentry의 tags를 사용하여 { errorType: 'database' }처럼 태그를 추가하면, 데이터베이스 관련 에러만 필터링하여 볼 수 있습니다. 이는 데이터베이스 장애와 애플리케이션 로직 에러를 구분하는 데 유용합니다.

💡 Timeout 에러를 추적하세요. 외부 API 호출 시 timeout을 설정하고, timeout 발생 시 Sentry에 기록하세요. 이를 통해 외부 서비스의 장애나 네트워크 문제를 빠르게 파악할 수 있습니다.

💡 에러 발생 시 자동 복구를 구현하세요. 특정 에러(예: 일시적인 DB 연결 오류)는 재시도 로직을 추가하고, 재시도 후에도 실패하면 Sentry에 기록하세요. 이렇게 하면 일시적인 에러와 실제 장애를 구분할 수 있습니다.

💡 Health Check 엔드포인트를 만들고 모니터링하세요. /api/health에서 데이터베이스 연결, 외부 API 상태를 체크하고, 문제가 있으면 Sentry에 기록하세요. 사용자가 에러를 경험하기 전에 선제적으로 문제를 발견할 수 있습니다.


3. Vercel Analytics로 성능 모니터링 - Core Web Vitals 추적

시작하며

여러분의 Next.js 앱이 에러는 없는데 사용자들이 "느리다"고 불평한 경험 있으신가요? Lighthouse에서는 좋은 점수가 나오는데 실제 사용자 환경에서는 로딩이 오래 걸리는 경우가 많습니다.

특히 3G 네트워크를 사용하는 모바일 사용자나 저사양 디바이스 사용자는 훨씬 느린 경험을 하게 됩니다. 성능 문제는 에러만큼이나 치명적입니다.

페이지 로딩이 3초 이상 걸리면 사용자의 절반이 이탈한다는 연구 결과도 있습니다. 하지만 개발자의 고사양 맥북에서는 문제를 느끼기 어렵고, 실제 사용자가 어떤 성능을 경험하는지 측정하기 어렵습니다.

바로 이럴 때 필요한 것이 Vercel Analytics입니다. 실제 사용자의 Core Web Vitals(LCP, FID, CLS)을 자동으로 수집하여 어느 페이지가 느린지, 어느 지역 사용자가 느린 경험을 하는지 파악할 수 있습니다.

개요

간단히 말해서, Vercel Analytics는 실제 사용자의 웹 성능 지표를 자동으로 수집하고 분석하는 Real User Monitoring(RUM) 도구입니다. 왜 이 도구가 필요한지 실무 관점에서 설명하면, Lighthouse 같은 Lab 데이터는 통제된 환경에서 측정한 것이라 실제 사용자 경험과 다를 수 있습니다.

예를 들어, 한국에서는 빠르지만 미국에서는 느린 경우, 모바일에서는 느리지만 데스크톱에서는 빠른 경우 등 다양한 변수가 있습니다. Vercel Analytics는 실제 사용자의 디바이스, 네트워크, 위치에서 측정한 데이터를 제공합니다.

기존에는 Google Analytics나 직접 구현한 성능 로깅으로 측정했다면, 이제는 Vercel이 Next.js와 완벽히 통합되어 추가 코드 없이도 자동으로 성능 데이터를 수집합니다. 특히 Next.js의 페이지 전환, 이미지 최적화, 폰트 로딩 등 프레임워크 특화 메트릭도 함께 제공됩니다.

Vercel Analytics의 핵심 특징은 첫째, Core Web Vitals(LCP, FID, CLS, TTFB)를 실시간으로 수집하여 Google 검색 순위에 영향을 미치는 성능 지표를 모니터링할 수 있습니다. 둘째, 페이지별, 국가별, 디바이스별로 성능을 세분화하여 어디를 최적화해야 하는지 명확히 알 수 있습니다.

셋째, Zero Config로 설정 없이도 자동으로 동작합니다. 이러한 특징들이 데이터 기반 성능 최적화를 가능하게 합니다.

코드 예제

// app/layout.tsx - Vercel Analytics 설정
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/next';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body>
        {children}
        {/* 실제 사용자 데이터 수집 */}
        <Analytics />
        {/* Core Web Vitals 측정 */}
        <SpeedInsights />
      </body>
    </html>
  );
}

설명

이것이 하는 일: Next.js 앱의 루트 레이아웃에 Analytics와 SpeedInsights 컴포넌트를 추가하여 실제 사용자의 성능 데이터를 자동으로 Vercel 대시보드로 전송합니다. 첫 번째로, <Analytics /> 컴포넌트가 렌더링되면서 사용자의 페이지 뷰, 클릭 이벤트, 커스텀 이벤트를 추적합니다.

이는 Google Analytics와 유사하지만 훨씬 가볍고 빠르며, Vercel 인프라와 완벽히 통합되어 있습니다. 사용자가 어느 페이지를 방문했는지, 어느 버튼을 클릭했는지 추적할 수 있습니다.

그 다음으로, <SpeedInsights /> 컴포넌트가 Core Web Vitals를 측정합니다. LCP(Largest Contentful Paint)는 가장 큰 콘텐츠가 렌더링되는 시간, FID(First Input Delay)는 사용자가 처음 상호작용할 때까지의 지연 시간, CLS(Cumulative Layout Shift)는 레이아웃이 얼마나 흔들리는지를 측정합니다.

이 세 지표는 구글 검색 랭킹에 직접적인 영향을 미칩니다. 이 컴포넌트들은 Web Vitals API를 사용하여 브라우저에서 직접 성능 데이터를 수집하고, Navigator.sendBeacon으로 페이지를 떠날 때도 데이터가 손실되지 않도록 전송합니다.

즉, 사용자가 빠르게 페이지를 닫아도 성능 데이터는 정확히 기록됩니다. Vercel 대시보드에서는 수집된 데이터를 시각화하여 "홈페이지의 LCP가 2.5초인데 이미지 로딩이 병목이다", "모바일 사용자의 CLS가 높은데 광고 배너가 원인이다" 같은 구체적인 인사이트를 얻을 수 있습니다.

또한 배포 버전별로 성능을 비교하여 "이번 배포 후 성능이 20% 개선되었다"는 것을 정량적으로 확인할 수 있습니다. 여러분이 이 설정을 사용하면 실제 사용자가 경험하는 성능을 실시간으로 모니터링할 수 있고, 성능 문제가 발생하면 즉시 알림을 받을 수 있습니다.

또한 A/B 테스트를 할 때 성능 영향을 측정하여 "새 디자인이 예쁘지만 LCP가 30% 느려졌다"는 것을 데이터로 확인할 수 있습니다.

실전 팁

💡 커스텀 이벤트를 추적하세요. track('purchase', { value: 100 })처럼 중요한 비즈니스 이벤트를 추적하면 성능과 전환율의 상관관계를 파악할 수 있습니다. "LCP가 1초 빨라지면 전환율이 10% 증가한다" 같은 인사이트를 얻을 수 있습니다.

💡 페이지별로 성능 목표를 설정하세요. 홈페이지는 LCP 2초 이하, 상세 페이지는 1.5초 이하처럼 목표를 정하고, Vercel 대시보드에서 알림을 설정하여 목표를 벗어나면 즉시 알림을 받으세요.

💡 지역별 성능을 분석하세요. 한국 사용자는 빠르지만 유럽 사용자가 느리다면 CDN 설정을 확인하거나 Edge Function을 사용하여 지역별로 최적화하세요. Vercel은 글로벌 CDN을 제공하므로 적절히 활용하면 큰 개선을 볼 수 있습니다.

💡 디바이스별 성능 차이를 주목하세요. 모바일과 데스크톱의 성능 차이가 크다면, 모바일용 번들 크기를 줄이거나 중요하지 않은 JavaScript를 lazy load 하세요. Next.js의 dynamic import를 활용하면 쉽게 구현할 수 있습니다.

💡 배포 전 성능 회귀를 체크하세요. Vercel은 PR마다 성능 점수를 자동으로 측정하여 코멘트로 남겨줍니다. 새 코드가 성능을 저하시키는지 배포 전에 확인하여 성능 회귀를 방지하세요.


4. LogRocket으로 세션 리플레이 - 사용자 화면 녹화와 디버깅

시작하며

여러분이 사용자로부터 "버튼을 눌렀는데 아무 반응이 없어요"라는 제보를 받았는데, 재현이 안 되는 경험 있으신가요? 사용자에게 콘솔을 열어달라고 하거나 스크린샷을 요청해도 정확한 상황을 파악하기 어렵습니다.

특히 복잡한 UI 상태나 여러 단계를 거쳐야 재현되는 버그는 설명만으로는 이해하기 힘듭니다. 이런 문제는 실제 서비스에서 매우 흔합니다.

사용자는 정확히 무엇을 했는지 기억하지 못하고, 개발자는 사용자의 환경을 재현할 수 없습니다. 결국 버그 리포트는 "재현 불가"로 닫히거나, 엄청난 시간을 들여 사용자와 여러 번 소통해야 합니다.

바로 이럴 때 필요한 것이 LogRocket입니다. 사용자의 화면을 녹화하고, 클릭, 입력, 네트워크 요청, Redux 액션까지 모든 것을 기록하여 버그가 발생한 순간을 영화 보듯이 다시 볼 수 있습니다.

개요

간단히 말해서, LogRocket은 사용자의 브라우저 세션을 녹화하고 재생할 수 있는 세션 리플레이 도구입니다. 왜 이 도구가 필요한지 실무 관점에서 설명하면, 사용자가 경험한 버그를 개발자가 정확히 재현하는 것은 매우 어렵습니다.

사용자의 브라우저 상태, 로그인 상태, 이전 액션들이 모두 영향을 미치기 때문입니다. 예를 들어, "장바구니에 상품을 추가했다가 삭제한 후 다시 추가하면 가격이 이상해요" 같은 복잡한 시나리오는 설명만으로는 이해하기 힘듭니다.

LogRocket을 사용하면 사용자가 한 모든 액션을 비디오처럼 다시 보면서 정확히 무슨 일이 일어났는지 파악할 수 있습니다. 기존에는 사용자에게 "F12를 누르고 콘솔 탭을 캡처해주세요"라고 요청하거나, Sentry의 Breadcrumb만으로 추측했다면, 이제는 사용자의 화면 전체를 녹화하여 버그가 발생한 순간의 UI 상태, 클릭 위치, 입력 값을 모두 볼 수 있습니다.

LogRocket의 핵심 특징은 첫째, 화면 녹화와 함께 네트워크 요청, 콘솔 로그, Redux/Vuex 같은 상태 관리 액션을 함께 기록합니다. 둘째, 민감한 정보를 자동으로 마스킹하여 비밀번호, 카드 번호 같은 정보는 녹화되지 않습니다.

셋째, Sentry와 통합하여 에러가 발생한 세션의 리플레이를 바로 볼 수 있습니다. 이러한 특징들이 버그 해결 시간을 10배 이상 단축시킵니다.

코드 예제

// app/layout.tsx - LogRocket 초기화
import LogRocket from 'logrocket';
import setupLogRocketReact from 'logrocket-react';
import * as Sentry from '@sentry/nextjs';

// 클라이언트 사이드에서만 실행
if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {
  // LogRocket 초기화
  LogRocket.init('your-app/your-project');

  // React 플러그인 설정
  setupLogRocketReact(LogRocket);

  // Sentry와 통합 - 에러 발생 시 세션 URL 자동 연결
  LogRocket.getSessionURL(sessionURL => {
    Sentry.configureScope(scope => {
      scope.setExtra('sessionURL', sessionURL);
    });
  });

  // 사용자 식별 (로그인 후 호출)
  // LogRocket.identify('user-id', { name: 'User Name', email: 'user@example.com' });
}

설명

이것이 하는 일: LogRocket SDK를 초기화하여 사용자의 브라우저 세션을 녹화하고, Sentry와 통합하여 에러 발생 시 해당 세션의 리플레이를 바로 볼 수 있도록 설정합니다. 첫 번째로, LogRocket.init()이 클라이언트 사이드에서만 실행되도록 typeof window !== 'undefined' 체크를 합니다.

Next.js는 서버 사이드 렌더링을 하기 때문에 서버에서 LogRocket을 실행하면 에러가 발생합니다. 또한 프로덕션 환경에서만 녹화하도록 설정하여 개발 중에는 불필요한 세션이 기록되지 않습니다.

그 다음으로, setupLogRocketReact()를 호출하여 React 컴포넌트의 props, state 변경도 함께 기록합니다. 이는 "왜 이 컴포넌트가 리렌더링되었는지", "props가 어떻게 변경되었는지"를 추적하는 데 매우 유용합니다.

Redux를 사용한다면 logrocket-redux를 추가하여 모든 액션과 상태 변경을 시간 순서대로 볼 수 있습니다. LogRocket.getSessionURL()은 현재 세션의 리플레이 URL을 가져와서 Sentry에 추가합니다.

이렇게 하면 Sentry 대시보드에서 에러를 클릭했을 때 "이 에러가 발생한 세션 녹화 보기" 링크가 자동으로 표시됩니다. 에러 메시지와 스택 트레이스만 보는 것이 아니라, 사용자가 에러 발생 전까지 무엇을 했는지 영화처럼 다시 볼 수 있습니다.

LogRocket.identify()는 로그인한 사용자를 식별하여 "특정 사용자의 모든 세션 보기"나 "이 사용자가 어떤 버그를 경험했는지" 추적할 수 있습니다. 예를 들어 VIP 고객이 불편을 겪었다면, 그 고객의 모든 세션을 검색하여 어떤 문제가 있었는지 파악하고 우선적으로 해결할 수 있습니다.

여러분이 이 설정을 사용하면 버그 리포트를 받았을 때 "재현해주세요"라고 요청할 필요 없이, LogRocket 대시보드에서 해당 사용자의 세션을 검색하여 녹화를 재생하면 됩니다. 사용자가 어떤 페이지에서 어떤 버튼을 클릭했고, 어떤 네트워크 요청이 실패했는지 모두 볼 수 있어서 버그 원인을 몇 분 안에 찾을 수 있습니다.

실전 팁

💡 민감한 정보를 반드시 마스킹하세요. LogRocket은 자동으로 type="password" 필드를 마스킹하지만, 추가로 class="logrocket-private"를 사용하여 특정 요소를 녹화에서 제외할 수 있습니다. 카드 번호, 주민번호 같은 필드는 반드시 제외하세요.

💡 네트워크 요청을 필터링하세요. 써드파티 API 키나 토큰이 포함된 요청은 LogRocket 설정에서 제외하세요. sanitizer 옵션을 사용하여 요청/응답 헤더나 바디의 특정 필드를 마스킹할 수 있습니다.

💡 중요한 이벤트를 태그로 표시하세요. LogRocket.track('Purchase', { value: 100 })처럼 중요한 이벤트를 추적하면, 나중에 "결제 완료한 세션만 필터링"해서 볼 수 있습니다. 이는 "결제 과정에서 발생한 버그"만 집중적으로 분석할 때 유용합니다.

💡 샘플링을 조정하여 비용을 절감하세요. 모든 세션을 녹화하면 비용이 많이 들 수 있으므로, LogRocket.init({ shouldCaptureIP: false, network: { requestSanitizer: ... } })처럼 샘플링 비율을 50%로 낮추거나, 로그인한 사용자만 녹화하도록 설정하세요.

💡 성능 영향을 모니터링하세요. LogRocket은 비동기로 작동하여 성능 영향이 적지만, 매우 복잡한 SPA에서는 약간의 오버헤드가 있을 수 있습니다. Vercel Analytics로 LogRocket 추가 전후의 성능을 비교하여 영향을 측정하세요.


5. 커스텀 메트릭으로 비즈니스 지표 추적 - 전환율과 사용자 행동 분석

시작하며

여러분의 서비스에서 "사용자가 회원가입은 많이 하는데 왜 결제로 이어지지 않을까?"라는 질문을 받은 적 있나요? Google Analytics로는 페이지뷰는 볼 수 있지만, "장바구니에 상품을 추가한 사용자 중 몇 %가 실제로 결제했는지" 같은 구체적인 퍼널 분석은 어렵습니다.

에러 모니터링과 성능 모니터링만으로는 부족합니다. 서비스가 정상적으로 작동하고 빠르더라도, 사용자가 원하는 액션을 완료하지 못한다면 비즈니스는 실패합니다.

"어느 단계에서 사용자가 이탈하는지", "어떤 기능이 실제로 사용되는지"를 측정해야 합니다. 바로 이럴 때 필요한 것이 커스텀 메트릭입니다.

Sentry, Vercel Analytics, LogRocket 모두 커스텀 이벤트를 추적할 수 있어서 비즈니스 핵심 지표를 실시간으로 모니터링할 수 있습니다.

개요

간단히 말해서, 커스텀 메트릭은 기술적 지표(에러율, 성능) 외에 비즈니스 지표(전환율, 사용자 행동)를 추적하는 방법입니다. 왜 커스텀 메트릭이 필요한지 실무 관점에서 설명하면, 서비스의 성공은 단순히 "에러가 없다"가 아니라 "사용자가 목표를 달성한다"입니다.

예를 들어, 이커머스에서는 "검색 → 상품 상세 → 장바구니 → 결제" 퍼널의 각 단계별 전환율을 측정해야 어느 단계를 개선해야 하는지 알 수 있습니다. "결제 페이지 로딩은 빠른데 결제 완료율이 낮다면 UX 문제가 있다"는 것을 데이터로 증명할 수 있습니다.

기존에는 Google Analytics나 Mixpanel 같은 별도의 분석 도구를 사용했다면, 이제는 이미 사용 중인 모니터링 도구에서 함께 추적할 수 있습니다. Sentry의 커스텀 메트릭, Vercel Analytics의 커스텀 이벤트, LogRocket의 커스텀 트랙을 활용하면 하나의 대시보드에서 기술 지표와 비즈니스 지표를 함께 볼 수 있습니다.

커스텀 메트릭의 핵심 특징은 첫째, 코드 한 줄로 추적을 시작할 수 있어 구현이 매우 간단합니다. 둘째, 에러 데이터와 연결하여 "결제 실패한 사용자가 어떤 에러를 겪었는지" 분석할 수 있습니다.

셋째, 실시간으로 업데이트되어 A/B 테스트나 신기능 출시 효과를 즉시 확인할 수 있습니다. 이러한 특징들이 데이터 드리븐 의사결정을 가능하게 합니다.

코드 예제

// lib/analytics.ts - 통합 분석 유틸리티
import * as Sentry from '@sentry/nextjs';
import { track } from '@vercel/analytics';
import LogRocket from 'logrocket';

export const trackEvent = (eventName: string, properties?: Record<string, any>) => {
  // Vercel Analytics에 이벤트 전송
  track(eventName, properties);

  // Sentry에 Breadcrumb 추가 (에러 발생 시 컨텍스트로 활용)
  Sentry.addBreadcrumb({
    category: 'user-action',
    message: eventName,
    level: 'info',
    data: properties,
  });

  // LogRocket에 커스텀 이벤트 추가
  if (typeof window !== 'undefined' && LogRocket) {
    LogRocket.track(eventName, properties);
  }
};

// 사용 예시
// trackEvent('Purchase', { orderId: '123', value: 50000, currency: 'KRW' });
// trackEvent('AddToCart', { productId: 'abc', price: 10000 });

설명

이것이 하는 일: 통합 분석 유틸리티 함수를 만들어 하나의 함수 호출로 Vercel Analytics, Sentry, LogRocket에 동시에 커스텀 이벤트를 전송합니다. 첫 번째로, trackEvent() 함수는 이벤트 이름과 속성을 받아서 여러 분석 도구에 동시에 전송합니다.

이렇게 통합 함수를 만들면 코드 중복을 줄이고, 나중에 분석 도구를 교체하거나 추가할 때 한 곳만 수정하면 됩니다. 예를 들어 Mixpanel을 추가하고 싶다면 이 함수에만 한 줄 추가하면 모든 곳에서 자동으로 Mixpanel에도 이벤트가 전송됩니다.

그 다음으로, Vercel Analytics의 track() 함수로 이벤트를 전송하여 대시보드에서 이벤트 발생 횟수, 트렌드, 전환 퍼널을 시각화할 수 있습니다. 예를 들어 "지난 주 대비 이번 주 결제 완료 이벤트가 20% 증가했다"는 것을 그래프로 확인할 수 있습니다.

Sentry의 addBreadcrumb()는 이벤트를 Breadcrumb으로 추가하여, 나중에 에러가 발생했을 때 "사용자가 에러 발생 전에 어떤 액션을 했는지" 추적할 수 있습니다. 예를 들어 "장바구니 추가 → 결제 페이지 진입 → 결제 API 에러" 순서로 Breadcrumb이 기록되어 있으면, 결제 API 에러가 특정 상품에서만 발생하는지 쉽게 파악할 수 있습니다.

LogRocket의 track() 함수는 세션 리플레이에 마커를 추가하여, 녹화 영상에서 "결제 완료 시점"을 빠르게 찾을 수 있습니다. 특정 이벤트가 발생한 세션만 필터링하여 "결제 실패한 사용자들의 세션만 보기" 같은 분석이 가능합니다.

여러분이 이 함수를 사용하면 결제, 회원가입, 상품 조회 같은 핵심 비즈니스 액션을 추적하여 전환율을 계산하고, A/B 테스트 효과를 측정하고, 어느 기능이 실제로 사용되는지 파악할 수 있습니다. "새 디자인으로 변경 후 결제 완료율이 15% 증가했다"는 것을 정량적으로 증명할 수 있습니다.

실전 팁

💡 중요한 이벤트만 추적하세요. 모든 클릭을 추적하면 노이즈가 많아서 중요한 인사이트를 놓칠 수 있습니다. "비즈니스 목표와 직접 연관된 액션"만 추적하세요. 예: 회원가입, 결제, 주요 기능 사용, 에러 발생 등.

💡 속성(properties)을 풍부하게 추가하세요. 단순히 "결제 완료"만 추적하지 말고, { orderId, value, paymentMethod, isFirstPurchase } 같은 추가 정보를 함께 전송하면 더 깊은 분석이 가능합니다. "첫 구매 사용자의 평균 주문 금액" 같은 세그먼트 분석이 가능해집니다.

💡 퍼널 분석을 설정하세요. "검색 → 상품 상세 → 장바구니 → 결제" 각 단계를 이벤트로 추적하고, Vercel Analytics나 별도의 대시보드에서 퍼널을 시각화하세요. 어느 단계에서 이탈률이 높은지 파악하여 우선적으로 개선할 수 있습니다.

💡 에러와 연결하여 분석하세요. Sentry에서 특정 에러가 발생한 사용자들의 Breadcrumb을 보면, 에러 발생 전에 어떤 이벤트가 있었는지 패턴을 찾을 수 있습니다. "결제 실패한 사용자들은 모두 '쿠폰 적용' 이벤트 직후에 에러가 발생했다" 같은 인사이트를 얻을 수 있습니다.

💡 실시간 대시보드를 만드세요. 커스텀 메트릭 데이터를 Vercel 대시보드나 Grafana, Datadog 같은 도구로 시각화하여 실시간으로 모니터링하세요. "오늘 결제 완료가 어제보다 50% 감소했다"는 것을 즉시 발견하여 빠르게 대응할 수 있습니다.


6. 알림과 온콜 시스템 구축 - 장애 발생 시 즉시 대응

시작하며

여러분이 주말에 휴식을 취하고 있는데, 월요일 출근하니 "토요일부터 결제가 안 됐어요"라는 제보를 받은 경험 있으신가요? 장애가 발생해도 아무도 모르고 있다가 사용자 제보로 뒤늦게 알게 되는 상황은 치명적입니다.

실시간 모니터링 도구를 설정했어도, 대시보드를 직접 확인하지 않으면 장애를 발견할 수 없습니다. 특히 새벽 시간이나 주말에 발생한 장애는 월요일 아침이 되어서야 발견되는 경우가 많습니다.

이는 사용자 이탈과 매출 손실로 직결됩니다. 바로 이럴 때 필요한 것이 알림과 온콜 시스템입니다.

에러율이 급증하거나, 성능이 저하되거나, 중요한 이벤트가 발생하면 자동으로 Slack, 이메일, SMS로 알림을 받아 즉시 대응할 수 있습니다.

개요

간단히 말해서, 알림 시스템은 모니터링 도구가 감지한 이상 징후를 개발팀에게 실시간으로 전달하는 자동화된 시스템입니다. 왜 알림 시스템이 필요한지 실무 관점에서 설명하면, 장애 발견이 1분 늦으면 사용자 경험 저하와 매출 손실이 기하급수적으로 증가합니다.

예를 들어, 결제 API가 다운되면 1분에 수십 명의 사용자가 결제에 실패하고, 1시간이면 수백만 원의 손실이 발생할 수 있습니다. 알림 시스템을 통해 장애를 즉시 발견하고 5분 안에 대응하면 피해를 최소화할 수 있습니다.

기존에는 개발자가 수동으로 대시보드를 확인하거나, 사용자 제보를 기다렸다면, 이제는 Sentry, Vercel, LogRocket이 자동으로 이상 징후를 감지하고 알림을 전송합니다. Slack으로 알림이 오면 팀원 누구든 즉시 확인하고 대응할 수 있습니다.

알림 시스템의 핵심 특징은 첫째, 심각도별로 알림 채널을 분리하여 중요한 알림만 SMS나 전화로 받을 수 있습니다. 둘째, 알림 규칙을 세밀하게 설정하여 "10분 내 동일 에러 20회 이상" 같은 조건으로 노이즈를 줄일 수 있습니다.

셋째, 온콜 로테이션을 설정하여 주말이나 야간에도 담당자가 즉시 대응할 수 있습니다. 이러한 특징들이 서비스 안정성과 신뢰도를 크게 향상시킵니다.

코드 예제

// sentry.client.config.ts - Sentry 알림 규칙 설정 예시
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

  // 알림 전송 전 조건 확인
  beforeSend(event, hint) {
    // 심각한 에러만 알림 (예: 결제 관련)
    if (event.tags?.critical === 'true') {
      // 추가 컨텍스트 포함
      event.contexts = {
        ...event.contexts,
        alert: {
          severity: 'high',
          notifyChannels: ['slack', 'email', 'sms'],
        },
      };
    }

    // 무시할 에러 필터링 (브라우저 익스텐션 에러 등)
    if (hint.originalException?.message?.includes('extension')) {
      return null;
    }

    return event;
  },
});

// 커스텀 에러 전송 예시
export const reportCriticalError = (error: Error, context?: Record<string, any>) => {
  Sentry.captureException(error, {
    tags: { critical: 'true' },
    contexts: { business: context },
    level: 'fatal',
  });
};

설명

이것이 하는 일: Sentry의 beforeSend 훅에서 에러의 심각도를 판단하고, 중요한 에러는 추가 컨텍스트를 포함하여 여러 채널로 알림을 전송하도록 설정합니다. 첫 번째로, beforeSend 훅은 에러가 Sentry로 전송되기 직전에 실행되어 에러의 태그를 확인합니다.

critical: 'true' 태그가 있는 에러는 결제, 회원가입, 데이터 손실처럼 비즈니스에 직접적인 영향을 미치는 중요한 에러입니다. 이런 에러는 severity: 'high'로 표시하고, Slack뿐만 아니라 이메일과 SMS로도 알림을 전송하도록 메타데이터를 추가합니다.

그 다음으로, 노이즈를 줄이기 위해 무시할 에러를 필터링합니다. 브라우저 익스텐션이나 광고 차단기로 인한 에러는 서비스 안정성과 무관하므로 return null로 전송하지 않습니다.

이렇게 하면 실제로 중요한 에러만 알림이 오므로 알림 피로도를 줄일 수 있습니다. reportCriticalError() 함수는 코드에서 명시적으로 중요한 에러를 보고할 때 사용합니다.

예를 들어 결제 API 호출이 실패했을 때 이 함수를 호출하면, 일반 에러와 구분되어 즉시 알림이 전송됩니다. level: 'fatal'은 Sentry에서 가장 높은 심각도로, 대시보드에서도 빨간색으로 강조 표시됩니다.

Sentry 대시보드에서는 Alert Rules를 설정하여 "10분 내 동일 에러 10회 이상 발생 시 Slack 알림", "fatal 레벨 에러 발생 즉시 SMS 전송" 같은 규칙을 만들 수 있습니다. 또한 PagerDuty나 Opsgenie 같은 온콜 관리 도구와 연동하여 주말/야간에는 온콜 담당자에게만 전화가 가도록 설정할 수 있습니다.

여러분이 이 시스템을 사용하면 장애가 발생한 지 1분 이내에 Slack 알림을 받고, 5분 이내에 원인을 파악하여 대응할 수 있습니다. "월요일 아침에 주말 동안의 장애를 발견"하는 상황을 완전히 방지할 수 있습니다.

실전 팁

💡 알림 피로도를 관리하세요. 너무 많은 알림은 오히려 중요한 알림을 놓치게 만듭니다. "1시간에 같은 에러 알림은 1번만" 같은 중복 제거 규칙을 설정하세요. Sentry는 자동으로 같은 에러를 그룹화하므로 이 기능을 활용하세요.

💡 심각도를 3단계로 구분하세요. Critical(즉시 대응 필요, SMS 전송), High(1시간 내 대응, Slack 알림), Low(다음 날 확인, 이메일만) 같이 구분하면 우선순위를 명확히 할 수 있습니다. 결제 에러는 Critical, UI 버그는 Low로 분류하세요.

💡 온콜 로테이션을 설정하세요. PagerDuty나 Opsgenie로 주간 온콜 담당자를 지정하고, 야간/주말에는 자동으로 온콜 담당자에게 전화가 가도록 설정하세요. 담당자가 5분 내 응답하지 않으면 다음 담당자에게 에스컬레이션되도록 설정할 수 있습니다.

💡 알림에 Runbook 링크를 추가하세요. Slack 알림에 "이 에러 해결 방법: [Runbook 링크]"를 포함하면, 경험이 적은 팀원도 빠르게 대응할 수 있습니다. 일반적인 에러는 해결 방법을 문서화하여 대응 시간을 단축하세요.

💡 알림 후 후속 조치를 추적하세요. Sentry에서 에러를 "Resolved"로 표시하면 자동으로 Slack에 "해결됨" 메시지를 보내도록 설정하세요. 이렇게 하면 팀 전체가 장애 상황을 실시간으로 파악할 수 있고, 중복 작업을 방지할 수 있습니다.


7. Health Check와 Uptime 모니터링 - 서비스 가용성 추적

시작하며

여러분의 서비스가 완전히 다운되었는데, 사용자가 트위터에 글을 올리고 나서야 알게 된 경험 있으신가요? 서버가 크래시되거나, 데이터베이스 연결이 끊어지거나, 외부 API가 다운되면 사용자는 아무것도 할 수 없지만, 에러 로그조차 남지 않을 수 있습니다.

에러 모니터링은 "에러가 발생했을 때" 알려주지만, 서비스가 완전히 다운되면 에러조차 전송되지 않습니다. 예를 들어 서버 프로세스가 종료되거나, 네트워크가 끊어지면 Sentry에 에러를 보낼 수도 없습니다.

이런 상황에서는 외부에서 주기적으로 서비스를 체크하는 Uptime 모니터링이 필수입니다. 바로 이럴 때 필요한 것이 Health Check Endpoint와 Uptime 모니터링입니다.

외부 서비스가 주기적으로 여러분의 서비스를 호출하여 정상 작동 여부를 확인하고, 다운되면 즉시 알림을 보냅니다.

개요

간단히 말해서, Uptime 모니터링은 외부에서 주기적으로 서비스를 호출하여 가용성을 확인하고, 다운 시 즉시 알림을 보내는 시스템입니다. 왜 Uptime 모니터링이 필요한지 실무 관점에서 설명하면, 서비스 다운타임은 직접적인 매출 손실과 신뢰도 하락으로 이어집니다.

특히 SLA(Service Level Agreement)를 보장해야 하는 B2B 서비스에서는 99.9% 가용성을 유지해야 하므로, 다운타임을 최소화하는 것이 매우 중요합니다. 예를 들어, 결제 서비스가 30분 다운되면 수백만 원의 손실이 발생하고, 고객사의 신뢰를 잃을 수 있습니다.

기존에는 수동으로 서비스를 체크하거나, 사용자 제보를 기다렸다면, 이제는 UptimeRobot, Pingdom, Better Uptime 같은 도구가 1분마다 자동으로 체크합니다. 3번 연속 실패하면 다운으로 판단하고 즉시 알림을 전송합니다.

Uptime 모니터링의 핵심 특징은 첫째, 전 세계 여러 지역에서 동시에 체크하여 특정 지역만 다운되었는지 확인할 수 있습니다. 둘째, Health Check Endpoint를 통해 단순히 서버가 살아있는지뿐만 아니라 데이터베이스, 외부 API 연결 상태도 확인할 수 있습니다.

셋째, 다운타임 기록을 자동으로 저장하여 월간 가용성 리포트를 생성할 수 있습니다. 이러한 특징들이 서비스 신뢰도를 보장합니다.

코드 예제

// app/api/health/route.ts - Health Check Endpoint
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { redis } from '@/lib/redis';

export async function GET() {
  const startTime = Date.now();
  const checks: Record<string, { status: string; latency?: number; error?: string }> = {};

  // 데이터베이스 연결 확인
  try {
    await prisma.$queryRaw`SELECT 1`;
    checks.database = { status: 'healthy', latency: Date.now() - startTime };
  } catch (error) {
    checks.database = { status: 'unhealthy', error: error.message };
  }

  // Redis 연결 확인
  try {
    await redis.ping();
    checks.redis = { status: 'healthy', latency: Date.now() - startTime };
  } catch (error) {
    checks.redis = { status: 'unhealthy', error: error.message };
  }

  // 외부 API 확인 (예: 결제 API)
  try {
    const res = await fetch('https://api.payment.com/health', { signal: AbortSignal.timeout(5000) });
    checks.paymentAPI = { status: res.ok ? 'healthy' : 'unhealthy', latency: Date.now() - startTime };
  } catch (error) {
    checks.paymentAPI = { status: 'unhealthy', error: 'timeout or unreachable' };
  }

  // 전체 상태 판단
  const isHealthy = Object.values(checks).every(check => check.status === 'healthy');

  return NextResponse.json(
    { status: isHealthy ? 'healthy' : 'unhealthy', checks, timestamp: new Date().toISOString() },
    { status: isHealthy ? 200 : 503 }
  );
}

설명

이것이 하는 일: /api/health 엔드포인트를 만들어 데이터베이스, Redis, 외부 API의 연결 상태를 확인하고, 모두 정상이면 200, 하나라도 문제가 있으면 503 상태 코드를 반환합니다. 첫 번째로, 데이터베이스 연결을 확인하기 위해 SELECT 1 쿼리를 실행합니다.

이는 가장 간단한 쿼리로 데이터베이스가 응답할 수 있는지만 확인합니다. 연결이 정상이면 status: 'healthy'와 함께 응답 시간(latency)을 기록합니다.

latency가 100ms를 넘으면 데이터베이스가 느려진 것이므로 추가 조사가 필요합니다. 그 다음으로, Redis 연결을 ping() 명령으로 확인합니다.

Redis는 세션, 캐시 등에 사용되므로 Redis가 다운되면 서비스가 매우 느려지거나 일부 기능이 작동하지 않을 수 있습니다. Redis 상태를 모니터링하여 문제를 조기에 발견할 수 있습니다.

외부 API 체크에서는 결제 API처럼 핵심 기능에 필요한 외부 서비스의 상태를 확인합니다. AbortSignal.timeout(5000)으로 5초 타임아웃을 설정하여, 외부 API가 응답하지 않으면 빠르게 실패 처리합니다.

외부 API가 다운되어도 Health Check Endpoint는 빠르게 응답해야 하므로 타임아웃이 필수입니다. 모든 체크가 완료되면 결과를 JSON으로 반환하고, 하나라도 unhealthy면 503(Service Unavailable) 상태 코드를 반환합니다.

UptimeRobot 같은 모니터링 도구는 이 엔드포인트를 1분마다 호출하여 200이 아니면 알림을 보냅니다. 여러분이 이 Health Check를 사용하면 서버는 정상이지만 데이터베이스가 다운된 상황, Redis는 정상이지만 외부 API가 느린 상황을 즉시 파악할 수 있습니다.

"서비스가 느리다"는 불분명한 제보 대신 "Redis 응답 시간이 200ms → 2000ms로 증가했다"는 구체적인 데이터를 얻을 수 있습니다.

실전 팁

💡 Health Check는 가볍게 유지하세요. 복잡한 쿼리나 무거운 계산은 피하고, 단순히 연결 상태만 확인하세요. Health Check 자체가 서버 부하를 증가시켜서는 안 됩니다. SELECT 1 같은 간단한 쿼리면 충분합니다.

💡 여러 엔드포인트를 체크하세요. /api/health는 전체 상태, /api/health/database는 DB만, /api/health/redis는 Redis만 체크하는 식으로 세분화하면 문제를 더 빠르게 찾을 수 있습니다. UptimeRobot에서 각각 별도로 모니터링하세요.

💡 인증 없이 접근 가능하게 하되, 민감한 정보는 제외하세요. Health Check는 누구나 호출할 수 있어야 외부 모니터링 도구가 사용할 수 있지만, 데이터베이스 버전이나 내부 IP 같은 정보는 노출하지 마세요. status: 'healthy' 정도만 공개하세요.

💡 Vercel의 Edge Middleware에서 Health Check를 구현하면 더 빠릅니다. API Route는 서버리스 함수로 cold start가 있을 수 있지만, Edge Middleware는 항상 실행 중이므로 응답이 빠릅니다. 간단한 ping만 체크한다면 Edge를 활용하세요.

💡 Status Page를 만드세요. status.yourdomain.com에 공개 Status Page를 만들어 사용자가 현재 서비스 상태를 확인할 수 있게 하세요. Better Uptime이나 Statuspage.io를 사용하면 자동으로 Health Check 결과를 반영한 Status Page를 만들 수 있습니다.


8. 로그 집계와 검색 - 프로덕션 로그를 효율적으로 관리

시작하며

여러분이 "12월 3일 오후 3시경에 특정 사용자가 결제 오류를 겪었다"는 제보를 받았는데, 로그를 찾기 위해 수십 개의 서버리스 함수 로그를 일일이 검색한 경험 있으신가요? Vercel이나 AWS Lambda는 각 함수마다 로그가 분리되어 있어서 전체 요청 흐름을 추적하기 어렵습니다.

로그는 디버깅의 핵심입니다. 하지만 분산된 환경에서 로그를 관리하는 것은 매우 어렵습니다.

특히 서버리스 아키텍처에서는 수백 개의 함수가 동시에 실행되고, 각각 별도의 로그를 생성하므로 특정 요청의 전체 흐름을 추적하기 거의 불가능합니다. 바로 이럴 때 필요한 것이 로그 집계(Log Aggregation) 시스템입니다.

모든 로그를 한 곳에 모아서 검색하고, 필터링하고, 시각화할 수 있습니다. Datadog, New Relic, Axiom 같은 도구를 사용하면 "특정 사용자의 모든 로그", "특정 시간대의 에러 로그"를 몇 초 만에 찾을 수 있습니다.

개요

간단히 말해서, 로그 집계는 분산된 여러 소스의 로그를 중앙 저장소에 모아서 검색하고 분석할 수 있게 하는 시스템입니다. 왜 로그 집계가 필요한지 실무 관점에서 설명하면, 프로덕션 환경에서는 하루에 수백만 줄의 로그가 생성됩니다.

Vercel의 경우 각 API Route마다 별도의 로그가 생기고, CloudWatch에 흩어져 있어서 특정 요청을 추적하려면 여러 로그 스트림을 일일이 확인해야 합니다. 예를 들어, "사용자가 결제 버튼을 눌렀는데 에러가 발생했다"는 제보를 받으면, 프론트엔드 로그, API Route 로그, 결제 API 로그를 모두 확인해야 하는데, 로그 집계가 없으면 몇 시간이 걸릴 수 있습니다.

기존에는 각 플랫폼의 로그 뷰어를 일일이 확인했다면, 이제는 Axiom 같은 도구에서 userId: "abc123"로 검색하면 해당 사용자의 모든 로그가 시간순으로 정렬되어 나옵니다. 프론트엔드에서 API를 호출하고, API에서 데이터베이스를 쿼리하고, 결과를 반환하는 전체 흐름을 하나의 타임라인에서 볼 수 있습니다.

로그 집계의 핵심 특징은 첫째, 구조화된 로그(Structured Logging)를 사용하여 JSON 형태로 로그를 저장하고 필드별로 검색할 수 있습니다. 둘째, Trace ID를 사용하여 하나의 요청이 여러 서비스를 거치는 흐름을 추적할 수 있습니다.

셋째, 로그 기반 메트릭을 생성하여 "5XX 에러 발생 빈도", "평균 API 응답 시간" 같은 지표를 자동으로 계산할 수 있습니다. 이러한 특징들이 빠른 디버깅과 시스템 가시성을 제공합니다.

코드 예제

// lib/logger.ts - 구조화된 로깅 유틸리티
import pino from 'pino';
import { v4 as uuidv4 } from 'uuid';

// Pino logger 초기화 (고성능 JSON logger)
export const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level: (label) => ({ level: label.toUpperCase() }),
  },
  // 프로덕션에서는 JSON으로 출력
  transport: process.env.NODE_ENV === 'development' ? {
    target: 'pino-pretty',
    options: { colorize: true },
  } : undefined,
});

// Request logger middleware
export const createRequestLogger = () => {
  const traceId = uuidv4();

  return logger.child({
    traceId,
    service: 'api',
    environment: process.env.VERCEL_ENV || 'development',
  });
};

// 사용 예시
// const log = createRequestLogger();
// log.info({ userId: '123', action: 'purchase' }, 'User completed purchase');
// log.error({ userId: '123', error: err.message }, 'Payment API failed');

설명

이것이 하는 일: Pino 라이브러리를 사용하여 구조화된 JSON 로그를 생성하고, Trace ID를 추가하여 하나의 요청이 여러 함수를 거치는 흐름을 추적할 수 있도록 합니다. 첫 번째로, pino 라이브러리는 Node.js에서 가장 빠른 로거 중 하나로, JSON 형태로 로그를 출력합니다.

기존의 console.log("User 123 purchased")는 텍스트라서 검색이 어렵지만, log.info({ userId: '123', action: 'purchase' })는 JSON이라 userId: "123"으로 즉시 검색할 수 있습니다. 이는 Datadog, Axiom 같은 로그 집계 도구에서 필드별 필터링을 가능하게 합니다.

그 다음으로, createRequestLogger()는 각 요청마다 고유한 traceId를 생성합니다. 예를 들어 사용자가 /api/checkout을 호출하면 traceId: "abc-123"이 생성되고, 이 API가 내부적으로 /api/payment를 호출할 때도 같은 traceId를 전달합니다.

나중에 Axiom에서 traceId: "abc-123"으로 검색하면 전체 요청 체인의 모든 로그를 시간순으로 볼 수 있습니다. logger.child()는 부모 로거의 설정을 상속받은 자식 로거를 생성합니다.

service: 'api', environment: 'production' 같은 공통 필드를 자동으로 포함하므로, 매번 반복해서 추가할 필요가 없습니다. 이는 로그의 일관성을 보장하고 검색을 쉽게 만듭니다.

프로덕션 환경에서는 JSON 로그가 stdout으로 출력되고, Vercel은 자동으로 이를 수집하여 로그 뷰어에 표시합니다. 여기에 Axiom이나 Datadog의 integration을 추가하면 로그가 자동으로 전송되어 중앙에서 검색할 수 있습니다.

개발 환경에서는 pino-pretty로 컬러풀하게 포맷팅하여 가독성을 높입니다. 여러분이 이 로깅 시스템을 사용하면 "12월 3일 오후 3시에 user-123이 결제 실패했다"는 제보를 받았을 때, Axiom에서 userId: "user-123" AND timestamp: "2024-12-03T15:00:00" 쿼리로 몇 초 만에 해당 사용자의 모든 로그를 찾을 수 있습니다.

어떤 API를 호출했고, 어떤 에러가 발생했고, 어떤 데이터를 전송했는지 모두 확인할 수 있습니다.

실전 팁

💡 민감한 정보를 로그에서 제거하세요. Pino의 redact 옵션을 사용하여 비밀번호, 토큰, 카드 번호 같은 필드를 자동으로 마스킹할 수 있습니다. redact: ['password', 'creditCard']처럼 설정하면 해당 필드가 [Redacted]로 대체됩니다.

💡 로그 레벨을 적절히 사용하세요. DEBUG는 개발 환경에서만, INFO는 중요한 비즈니스 이벤트, WARN은 잠재적 문제, ERROR는 실제 에러에만 사용하세요. 프로덕션에서는 LOG_LEVEL=info로 설정하여 DEBUG 로그는 출력하지 않아 로그 볼륨과 비용을 줄이세요.

💡 Trace ID를 HTTP 헤더로 전달하세요. 프론트엔드에서 API를 호출할 때 X-Trace-ID 헤더에 UUID를 포함하면, 프론트엔드 로그와 백엔드 로그를 같은 Trace ID로 연결할 수 있습니다. 사용자 액션부터 API 응답까지 전체 흐름을 하나의 타임라인에서 볼 수 있습니다.

💡 로그 보존 기간을 설정하세요. 로그 저장 비용은 매우 빠르게 증가합니다. Axiom이나 Datadog에서 "ERROR 로그는 90일, INFO 로그는 30일" 같이 레벨별로 보존 기간을 다르게 설정하여 비용을 절감하세요.

💡 로그 기반 알림을 설정하세요. "5분 내 ERROR 로그 10건 이상" 같은 조건으로 알림을 설정하면, 에러가 급증하는 상황을 즉시 감지할 수 있습니다. 이는 Sentry와 중복되지만, Sentry가 놓칠 수 있는 비정상적인 패턴을 로그로 발견할 수 있습니다.


9. 배포 추적과 Release Health - 배포가 서비스에 미치는 영향 분석

시작하며

여러분이 금요일 오후에 신기능을 배포했는데, 주말 동안 에러율이 급증했다가 월요일에야 발견한 경험 있으신가요? 새 배포가 버그를 포함했는지, 성능을 저하시켰는지를 배포 직후에 즉시 파악하는 것은 매우 중요합니다.

배포는 항상 리스크를 동반합니다. 아무리 철저히 테스트해도 프로덕션 환경에서만 발생하는 문제가 있을 수 있습니다.

특히 트래픽 패턴, 데이터 분포, 외부 API 상태 같은 변수는 로컬이나 스테이징에서 재현하기 어렵습니다. 배포 후 몇 분 내에 문제를 발견하지 못하면 수천 명의 사용자가 영향을 받을 수 있습니다.

바로 이럴 때 필요한 것이 배포 추적(Release Tracking)입니다. Sentry, Vercel Analytics, Datadog 모두 배포 버전을 추적하여 "이번 배포 후 에러율이 증가했는지", "성능이 저하되었는지"를 자동으로 비교하고 알림을 보냅니다.

개요

간단히 말해서, 배포 추적은 각 배포 버전의 에러율, 성능, 사용자 영향을 자동으로 측정하고 이전 버전과 비교하는 시스템입니다. 왜 배포 추적이 필요한지 실무 관점에서 설명하면, 배포는 변경의 단위이고, 문제의 원인을 찾을 때 "언제부터 발생했는지"가 가장 중요한 힌트입니다.

예를 들어, 에러율이 갑자기 증가했다면 "가장 최근 배포에서 무엇을 변경했는지" 확인하면 원인을 빠르게 찾을 수 있습니다. 배포 추적 없이는 "며칠 전부터 문제가 있었던 것 같은데 정확히 언제부터인지 모르겠다"는 상황에 빠집니다.

기존에는 수동으로 배포 전후의 메트릭을 비교했다면, 이제는 Sentry의 Release Health가 자동으로 "v1.2.3 배포 후 에러율 200% 증가, 즉시 롤백 권장"이라는 알림을 보냅니다. Vercel Analytics는 배포 후 성능 변화를 그래프로 보여주어 "이번 배포 후 LCP가 1.5초에서 2.5초로 증가했다"는 것을 시각적으로 확인할 수 있습니다.

배포 추적의 핵심 특징은 첫째, Git 커밋 SHA를 release 버전으로 사용하여 정확히 어떤 코드 변경이 문제를 일으켰는지 추적할 수 있습니다. 둘째, Crash-free rate를 자동으로 계산하여 "99.9%의 사용자가 에러 없이 사용했다"는 지표를 제공합니다.

셋째, 배포 후 자동으로 이전 버전과 비교하여 회귀(regression)를 감지합니다. 이러한 특징들이 안전한 배포와 빠른 롤백을 가능하게 합니다.

코드 예제

// next.config.js - Sentry Release 자동 업로드
const { withSentryConfig } = require('@sentry/nextjs');

const nextConfig = {
  // Next.js 설정
};

module.exports = withSentryConfig(
  nextConfig,
  {
    // Sentry Webpack 플러그인 옵션
    silent: true, // 빌드 로그 숨김
    org: 'your-org',
    project: 'your-project',

    // Release 자동 생성 및 배포 추적
    release: {
      name: process.env.VERCEL_GIT_COMMIT_SHA,
      deploy: {
        env: process.env.VERCEL_ENV || 'development',
      },
    },

    // Source Map 업로드 (프로덕션만)
    widenClientFileUpload: true,
    hideSourceMaps: true,
  },
  {
    // Sentry CLI 옵션
    disableLogger: true,
  }
);

설명

이것이 하는 일: Sentry의 Next.js SDK를 사용하여 빌드 시 자동으로 Release를 생성하고, Source Map을 업로드하여 배포 버전별로 에러를 추적할 수 있도록 설정합니다. 첫 번째로, withSentryConfig()는 Next.js 빌드 프로세스에 Sentry Webpack 플러그인을 통합합니다.

빌드가 완료되면 자동으로 Sentry에 새 Release를 생성하고, VERCEL_GIT_COMMIT_SHA를 release 이름으로 사용합니다. 이렇게 하면 Sentry 대시보드에서 "커밋 abc123에서 에러가 10건 발생했다"는 것을 즉시 확인하고, GitHub에서 해당 커밋의 코드 변경을 바로 볼 수 있습니다.

그 다음으로, deploy.env를 설정하여 동일한 코드라도 production과 preview 환경을 구분합니다. Vercel은 PR마다 preview 배포를 생성하는데, 이를 프로덕션과 분리하여 추적하면 "preview 환경에서는 문제없었는데 프로덕션에서만 에러가 발생했다"는 것을 파악할 수 있습니다.

widenClientFileUpload: true는 클라이언트 번들뿐만 아니라 모든 JavaScript 파일의 Source Map을 업로드합니다. Next.js는 여러 청크로 코드를 분할하는데, 모든 청크의 Source Map을 업로드해야 에러 발생 위치를 정확히 파악할 수 있습니다.

hideSourceMaps: true는 프로덕션 번들에서 Source Map을 제거하여 사용자가 원본 코드를 볼 수 없게 보호합니다. Sentry는 업로드된 Source Map을 사용하여 minify된 프로덕션 코드의 스택 트레이스를 원본 TypeScript 코드로 변환합니다.

예를 들어 chunk-abc.js:1:2345라는 에러를 components/Checkout.tsx:42:10으로 변환하여 정확히 어느 파일의 어느 라인에서 에러가 발생했는지 보여줍니다. 여러분이 이 설정을 사용하면 배포 후 Sentry 대시보드에서 "이번 배포의 Crash-free rate는 99.5%로 이전 배포의 99.9%보다 낮습니다"라는 알림을 받을 수 있습니다.

문제가 있다고 판단되면 Vercel에서 이전 배포로 즉시 롤백할 수 있습니다.

실전 팁

💡 배포 후 30분간 집중 모니터링하세요. 대부분의 배포 문제는 배포 직후 30분 이내에 발견됩니다. Sentry와 Vercel Analytics 대시보드를 열어두고, 에러율과 성능 지표를 확인하세요. 금요일 오후 배포는 피하고, 월요일 오전에 배포하여 문제 발생 시 즉시 대응할 수 있도록 하세요.

💡 Canary 배포를 활용하세요. Vercel의 트래픽 분할 기능으로 새 버전을 전체 사용자의 5%에게만 먼저 배포하고, 30분간 문제가 없으면 100%로 확대하세요. 이렇게 하면 문제가 있어도 소수의 사용자만 영향을 받습니다.

💡 자동 롤백 규칙을 설정하세요. Sentry나 Datadog에서 "에러율이 이전 배포 대비 2배 증가 시 Slack 알림"을 설정하면, 심각한 문제를 즉시 발견할 수 있습니다. 더 나아가 Vercel CLI로 자동 롤백 스크립트를 만들 수 있습니다.

💡 배포 노트를 작성하세요. Sentry의 Release에 "결제 로직 리팩토링, 새 할인 기능 추가" 같은 설명을 추가하면, 나중에 에러를 분석할 때 "아, 이 배포에서 결제 로직을 변경했구나"라고 즉시 파악할 수 있습니다.

💡 배포 빈도를 높이세요. 작은 변경을 자주 배포하면 문제가 발생해도 원인을 쉽게 찾을 수 있습니다. "2주 동안 개발한 대형 기능을 한 번에 배포"하면 문제가 발생했을 때 어떤 변경이 원인인지 찾기 어렵습니다. 대신 "매일 작은 변경을 배포"하면 문제의 범위를 좁힐 수 있습니다.


10. 성능 프로파일링과 병목 지점 찾기 - 느린 코드 최적화

시작하며

여러분의 API가 평소엔 빠른데 특정 상황에서만 10초 이상 걸리는 경험 있으신가요? Vercel Analytics에서 "평균 응답 시간 500ms"라고 나오지만, 일부 요청은 5초 이상 걸려서 사용자가 불만을 제기하는 경우가 있습니다.

평균 지표만으로는 부족합니다. 99 percentile(상위 1%의 느린 요청)이 사용자 경험에 큰 영향을 미치는데, 평균은 이를 숨깁니다.

예를 들어 99%의 요청은 200ms인데 1%는 10초라면, 평균은 300ms로 좋아 보이지만 100명 중 1명은 매우 나쁜 경험을 합니다. 특히 VIP 고객이 그 1%에 해당한다면 큰 문제입니다.

바로 이럴 때 필요한 것이 성능 프로파일링(Performance Profiling)입니다. 코드의 어느 부분이 느린지, 어떤 데이터베이스 쿼리가 병목인지, 어떤 외부 API 호출이 타임아웃에 가까운지 정확히 측정하고 최적화할 수 있습니다.

개요

간단히 말해서, 성능 프로파일링은 코드 실행 시간을 함수별, 구간별로 측정하여 병목 지점을 찾아내는 방법입니다. 왜 성능 프로파일링이 필요한지 실무 관점에서 설명하면, "느리다"는 것은 주관적이고 막연합니다.

"어디가 느린지" 정확히 측정해야 최적화할 수 있습니다. 예를 들어, 사용자 목록 API가 느리다면 "데이터베이스 쿼리가 2초 걸린다", "JSON 직렬화가 1초 걸린다", "외부 프로필 이미지 로딩이 3초 걸린다" 중 어느 것이 원인인지 알아야 적절한 해결책을 적용할 수 있습니다.

기존에는 코드에 console.time() / console.timeEnd()를 일일이 추가했다면, 이제는 OpenTelemetry나 Sentry의 Performance Monitoring이 자동으로 함수 실행 시간, 데이터베이스 쿼리 시간, HTTP 요청 시간을 추적합니다. Waterfall 그래프로 시각화하여 어떤 작업이 순차적으로 실행되고, 어떤 부분에서 시간을 낭비하는지 한눈에 볼 수 있습니다.

성능 프로파일링의 핵심 특징은 첫째, 분산 추적(Distributed Tracing)으로 하나의 요청이 여러 서비스를 거치는 전체 흐름을 추적할 수 있습니다. 둘째, N+1 쿼리 같은 일반적인 성능 안티패턴을 자동으로 감지합니다.

셋째, 프로덕션 환경에서 실제 사용자 데이터로 측정하여 로컬에서 재현하기 어려운 문제를 발견할 수 있습니다. 이러한 특징들이 데이터 기반 성능 최적화를 가능하게 합니다.

코드 예제

// lib/performance.ts - 커스텀 성능 측정
import * as Sentry from '@sentry/nextjs';

export const measurePerformance = async <T>(
  operationName: string,
  operation: () => Promise<T>,
  metadata?: Record<string, any>
): Promise<T> => {
  // Sentry Transaction 시작
  const transaction = Sentry.startTransaction({
    name: operationName,
    op: 'function',
    data: metadata,
  });

  const startTime = Date.now();

  try {
    const result = await operation();
    const duration = Date.now() - startTime;

    // 느린 작업 경고 (1초 이상)
    if (duration > 1000) {
      console.warn(`Slow operation: ${operationName} took ${duration}ms`);
    }

    transaction.setStatus('ok');
    return result;
  } catch (error) {
    transaction.setStatus('internal_error');
    throw error;
  } finally {
    transaction.finish();
  }
};

// 사용 예시
// const users = await measurePerformance('fetchUsers', () => prisma.user.findMany(), { count: 100 });

설명

이것이 하는 일: Sentry의 Performance Monitoring API를 사용하여 특정 함수나 작업의 실행 시간을 측정하고, 1초 이상 걸리면 경고를 출력하며, 모든 데이터를 Sentry로 전송합니다. 첫 번째로, Sentry.startTransaction()은 새로운 트랜잭션을 시작하여 성능 추적을 시작합니다.

트랜잭션은 하나의 논리적 작업 단위로, 예를 들어 "사용자 목록 조회" 전체 과정을 하나의 트랜잭션으로 측정할 수 있습니다. operationName은 Sentry 대시보드에서 이 트랜잭션을 식별하는 이름이고, metadata는 추가 컨텍스트로 "몇 개의 사용자를 조회했는지" 같은 정보를 포함합니다.

그 다음으로, operation() 함수를 실행하고 시작 시간과 종료 시간을 측정하여 실행 시간을 계산합니다. 1초 이상 걸리면 console.warn()으로 경고를 출력하여 개발자가 로그에서 느린 작업을 즉시 발견할 수 있습니다.

프로덕션 환경에서는 이 경고가 로그 집계 시스템으로 전송되어 "어떤 작업이 자주 느려지는지" 패턴을 분석할 수 있습니다. 에러가 발생하면 transaction.setStatus('internal_error')로 트랜잭션을 실패로 표시하고, 성공하면 ok로 표시합니다.

Sentry 대시보드에서 성공률을 확인하여 "이 작업의 95%는 성공했지만 5%는 실패했다"는 것을 알 수 있습니다. 실패한 트랜잭션만 필터링하여 어떤 에러가 발생했는지 분석할 수 있습니다.

transaction.finish()는 finally 블록에서 호출되어 성공이든 실패든 항상 트랜잭션을 종료하고 Sentry로 데이터를 전송합니다. Sentry는 이 데이터를 수집하여 평균 실행 시간, p50/p95/p99 percentile, 최대 실행 시간을 자동으로 계산하고 그래프로 시각화합니다.

여러분이 이 유틸리티를 사용하면 "사용자 목록 조회는 평균 300ms인데 p95는 2초다"라는 것을 발견하고, "특정 조건(예: 사용자가 1000명 이상)에서만 느려진다"는 패턴을 찾아낼 수 있습니다. 그리고 데이터베이스 인덱스를 추가하거나 쿼리를 최적화하여 p95를 500ms로 개선할 수 있습니다.

실전 팁

💡 데이터베이스 쿼리를 개별 Span으로 측정하세요. Sentry의 transaction.startChild({ op: 'db.query', description: 'SELECT * FROM users' })로 각 쿼리를 별도로 추적하면, Waterfall 그래프에서 어느 쿼리가 느린지 한눈에 볼 수 있습니다.

💡 N+1 쿼리를 찾아내세요. 사용자 목록을 조회할 때 각 사용자마다 별도로 프로필 이미지를 조회하면 100명이면 101번의 쿼리가 발생합니다. Sentry의 쿼리 횟수를 보고 N+1을 발견하면, include나 JOIN으로 한 번에 조회하도록 최적화하세요.

💡 외부 API 호출을 타임아웃과 함께 측정하세요. fetch()signal: AbortSignal.timeout(5000)을 추가하고, 타임아웃이 발생하면 Sentry에 기록하세요. 어떤 외부 API가 자주 느려지는지 파악하여 해당 API를 교체하거나 캐싱을 추가할 수 있습니다.

💡 캐시 히트율을 측정하세요. Redis 캐시를 사용한다면, 캐시 히트/미스를 Sentry에 기록하여 캐시 효율성을 추적하세요. "캐시 히트율이 50%밖에 안 된다"면 캐시 키 설계를 개선하거나 TTL을 조정할 수 있습니다.

💡 메모리 사용량도 모니터링하세요. Node.js의 process.memoryUsage()로 메모리 사용량을 측정하고, 메모리 누수가 의심되면 Chrome DevTools의 Heap Snapshot으로 프로파일링하세요. 서버리스 환경에서는 메모리 제한이 엄격하므로 메모리 최적화가 중요합니다.


#Next.js#Sentry#Monitoring#ErrorTracking#Analytics

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.