본문으로 건너뛰기

안동민 개발노트

본문 시작

서버 사이드 로깅 및 모니터링

서버 컴포넌트·Route Handler·Proxy에 구조화 로그를 남기고 Vercel과 APM에서 오류·지연을 관찰합니다.

Next.js 애플리케이션은 브라우저(클라이언트)와 Node.js 환경(서버)에서 함께 실행됩니다.

앞 절에서 클라이언트 디버깅을 다뤘다면, 이번 절은 서버 사이드 로깅(Server-side Logging)모니터링(Monitoring)에 초점을 맞춥니다.

특히 서버 컴포넌트, Route Handler, Proxy에서 발생하는 문제를 어떻게 진단하고 해결할지 실전 관점에서 정리합니다.

먼저 서버 코드의 어느 경계에서 어떤 로그를 남겨야 하는지 요청 흐름 기준으로 잡아 봅니다.

서버 문제는 요청 ID, 위치, 레벨, 사용자 영향으로 추적한다

브라우저에 보이지 않는 서버 오류는 어느 코드 경계에서 발생했고 누구에게 영향을 줬는지 남겨야 다시 찾을 수 있다.

관측 위치남길 로그확인할 곳다음 행동
Server Componentroute, params, data source, render 실패터미널, Vercel Runtime Logs데이터 조회와 권한 조건 분리
Route Handler/APImethod, status, duration, requestIdNetwork 응답과 서버 로그입력 검증, DB, 외부 API 중 병목 지정
Server Actionaction name, userId, validation result서버 로그, form 반환값재시도 가능 오류와 사용자 오류 분리
Proxypath, auth state, redirect targetVercel Runtime Logs쿠키, matcher, 권한 조건 확인
DB/외부 APIquery name, latency, timeout, retry countAPM, DB slow log쿼리, 인덱스, 네트워크 지연 분리

서버 사이드 로깅의 중요성

서버 로그는 화면에 바로 드러나지 않는 실패를 오류, 성능, 사용자 영향, 보안 신호로 바꿔 줍니다.

서버 로그는 보이지 않는 실패를 사용자 영향과 운영 신호로 바꾼다

서버 오류는 화면에 조용히 실패처럼 보일 수 있다. 로그는 오류, 성능, 보안, 디버깅 단서를 같은 형식으로 남긴다.

목적예시 신호필요한 필드놓치면 생기는 문제
오류 추적500, exception, rejected promisestack, requestId, route, input summary재현 없이 원인 추측만 반복
성능 병목느린 API, 긴 DB queryduration, query name, upstream latency느린 화면과 서버 비용을 연결 못 함
사용자 영향특정 사용자/테넌트 반복 실패userId hash, plan, feature flag장애 범위와 우선순위 판단 실패
보안 감사인증 실패, 권한 우회 시도ip, path, auth result, reason공격 징후를 사후에 복원 못 함
프로덕션 디버깅배포 후에만 발생하는 오류env, deployment id, version로컬 정상 여부만 확인하고 멈춤

클라이언트 측 오류는 브라우저 개발자 도구 콘솔에서 쉽게 확인할 수 있지만, 서버 측에서 발생하는 오류나 예외는 사용자에게 직접적으로 노출되지 않을 수 있습니다.

서버 사이드 로깅은 다음과 같은 이유로 매우 중요합니다.

  • 오류 및 예외 추적: 서버에서 발생하는 런타임 오류, 데이터베이스 연결 문제, 외부 API 호출 실패 등 예측 불가능한 문제를 기록하여 신속하게 진단하고 수정할 수 있습니다.
  • 성능 병목 현상 식별: 특정 API 요청의 응답 시간, 데이터베이스 쿼리 시간 등을 로깅하여 성능 저하의 원인을 파악할 수 있습니다.
  • 사용자 행동 분석: 사용자의 요청 패턴, 특정 기능 사용 빈도 등을 로깅하여 애플리케이션 개선을 위한 통찰력을 얻을 수 있습니다.
  • 보안 감사: 비정상적인 접근 시도, 인증 실패 등을 기록하여 보안 위협을 감지하고 대응할 수 있습니다.
  • 디버깅 용이성: 프로덕션 환경에서는 브레이크포인트를 사용할 수 없으므로, 상세한 로그는 문제 발생 시 유일한 디버깅 단서가 됩니다.

Next.js에서 서버 사이드 로깅 구현

Next.js는 Node.js 환경에서 실행되므로, 표준 Node.js 로깅 방식을 따릅니다.

기본 console.log 활용

가장 간단한 방법은 console.log, console.error, console.warn 등을 사용하는 것입니다.

  • 위치
    • Route Handler: app 디렉터리의 route.ts에 정의한 HTTP 메서드 함수.
    • Server Components: app 디렉토리 내의 서버 컴포넌트.
    • Server Actions: actions 파일 내의 서버 액션 함수.
    • Proxy: proxy.ts 파일.
    • 데이터베이스 연결 파일: lib/db.ts 등.
  • 확인 방법
    • 로컬 개발 환경: npm run dev 또는 yarn dev로 실행된 터미널에 출력됩니다.
    • Vercel 배포 환경: Vercel 대시보드의 특정 배포에 대한 Logs 탭에서 확인할 수 있습니다.
  • 예시
    app/api/books/route.ts (Route Handler)
    import { NextResponse } from 'next/server';
    import connectToDatabase from '@/lib/db';
    import Book from '@/models/Book';
    
    export async function GET() {
      try {
        console.log('GET /api/books 요청 수신'); // 서버 측 로그
        await connectToDatabase();
        const books = await Book.find({});
        console.log(`총 ${books.length}권의 책을 찾았습니다.`); // 서버 측 로그
        return NextResponse.json(books);
      } catch (error) {
        console.error('API /api/books 처리 중 오류 발생:', error); // 서버 측 오류 로그
        return NextResponse.json({ error: 'Failed to fetch books' }, { status: 500 });
      }
    }
    app/books/[id]/page.tsx (Server Component)
    import connectToDatabase from '@/lib/db';
    import Book, { IBook } from '@/models/Book';
    
    interface BookDetailPageProps {
      params: Promise<{ id: string }>;
    }
    
    export default async function BookDetailPage({ params }: BookDetailPageProps) {
      const { id } = await params;
      console.log(`도서 상세 페이지 로드: ID ${id}`); // 서버 측 로그
      await connectToDatabase();
      const book: IBook | null = await Book.findById(id).lean();
    
      if (!book) {
        console.warn(`ID ${id}에 해당하는 책을 찾을 수 없습니다.`); // 서버 측 경고 로그
        // notFound();
      }
      // ...
    }

로깅 라이브러리 활용 (Winston, Pino 등)

프로덕션 환경에서는 console.log만으로는 부족합니다.

더 체계적이고 유연한 로깅을 위해 전문 로깅 라이브러리를 사용하는 것이 좋습니다.

  • 장점
    • 로그 레벨: debug, info, warn, error 등 다양한 로그 레벨을 지원하여 중요도에 따라 로그를 필터링할 수 있습니다.
    • 로그 포맷: JSON, 텍스트 등 다양한 포맷으로 로그를 출력할 수 있어 로그 분석 도구와 연동하기 용이합니다.
    • 전송: 파일, 데이터베이스, 외부 로깅 서비스(Datadog, Sentry, CloudWatch 등)로 로그를 전송할 수 있습니다.
    • 컨텍스트: 요청 ID, 사용자 ID 등 요청 관련 컨텍스트 정보를 로그에 자동으로 추가할 수 있습니다.
  • 예시 (Winston)

    설치: npm install winston

    lib/logger.ts 생성
    lib/logger.ts
    import { createLogger, format, transports } from 'winston';
    
    const { combine, timestamp, printf, colorize, align } = format;
    
    const logFormat = printf(({ level, message, timestamp, stack }) => {
      return `${timestamp} ${level}: ${message}${stack ? `\n${stack}` : ''}`;
    });
    
    const logger = createLogger({
      level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', // 프로덕션에서는 info 이상, 개발에서는 debug 이상
      format: combine(
        timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        logFormat,
        // 프로덕션에서는 JSON 포맷 권장
        // process.env.NODE_ENV === 'production' ? format.json() : colorize({ all: true })
      ),
      transports: [
        new transports.Console(), // 콘솔에 출력
        // 프로덕션에서는 파일 또는 외부 서비스로 전송
        // new transports.File({ filename: 'error.log', level: 'error' }),
        // new transports.File({ filename: 'combined.log' }),
      ],
    });
    
    export default logger;
    사용
    app/api/books/route.ts
    import { NextResponse } from 'next/server';
    import connectToDatabase from '@/lib/db';
    import Book from '@/models/Book';
    import logger from '@/lib/logger'; // 로거 임포트
    
    export async function GET() {
      try {
        logger.info('GET /api/books 요청 수신');
        await connectToDatabase();
        const books = await Book.find({});
        logger.debug(`총 ${books.length}권의 책을 찾았습니다.`);
        return NextResponse.json(books);
      } catch (error: any) {
        logger.error('API /api/books 처리 중 오류 발생:', error.message, { stack: error.stack });
        return NextResponse.json({ error: 'Failed to fetch books' }, { status: 500 });
      }
    }

다음 다이어그램은 서버 로그 한 줄에 어떤 필드를 남겨야 추적과 알림까지 이어지는지 정리한 것입니다.

로그 한 줄은 시간, 레벨, 요청 ID, 위치, 결과를 함께 가져야 추적된다

좋은 로그는 문장 감상이 아니라 검색 가능한 사건 기록이다. 같은 요청 ID로 브라우저 증상과 서버 처리를 이어 읽는다.

필드예시쓰는 이유알림 연결
timestamp2026-06-23T08:12:30Z요청 흐름과 배포 시점을 맞춤특정 시간대 오류 급증 탐지
levelinfo, warn, error운영자가 볼 우선순위 구분error 비율 기준 알림
requestIdreq_7f4c한 사용자의 요청 흐름을 묶음분산 로그 검색 키
whereGET /api/books, ServerAction:createBook수정할 코드 경계를 바로 찾음엔드포인트별 실패율
resultstatus=500 duration=820ms성공/실패와 비용을 함께 기록지연 시간·오류 임계치

애플리케이션 모니터링

로깅은 발생한 이벤트와 오류를 기록하는 것이지만, 모니터링은 이러한 로그와 메트릭(metric)을 수집, 시각화하고, 시스템의 상태와 성능을 지속적으로 감시하는 활동입니다.

Vercel 대시보드 및 Logs

Vercel은 Next.js 애플리케이션 배포에 최적화되어 있으며, 기본 로깅 및 모니터링 기능을 제공합니다.

  • Logs 탭
    • 용도: 배포된 애플리케이션의 서버 함수(Route Handler, Server Components, Server Actions, Proxy)에서 발생하는 console.log와 오류를 확인할 수 있습니다.
    • 활용: 프로덕션 환경에서 오류가 발생했을 때 가장 먼저 확인해야 할 곳입니다. 필터링, 검색 기능을 통해 특정 요청이나 시간대의 로그를 쉽게 찾을 수 있습니다.
  • Usage 탭
    • 용도: 배포된 애플리케이션의 트래픽, 함수 호출 횟수, 데이터 전송량 등 사용량 통계를 제공합니다.
    • 활용: 애플리케이션의 인기도나 부하를 파악하고, 비용 예측에 활용할 수 있습니다.
  • Speed Insights
    • 용도: 실제 사용자 데이터(Real User Monitoring, RUM)를 기반으로 Core Web Vitals를 포함한 페이지 성능 지표를 모니터링합니다.
    • 활용: 개발 환경에서의 테스트를 넘어, 실제 사용자들이 어떤 성능을 경험하는지 객관적인 데이터를 제공하여 성능 개선의 우선순위를 정하는 데 도움을 줍니다.

외부 APM 도구 연동

대규모 애플리케이션이나 복잡한 인프라를 가진 경우, Vercel 기본 모니터링 외에 전문 APM 도구 (Application Performance Monitoring)를 연동하는 것이 좋습니다.

  • Sentry
    • 용도: 실시간 오류 추적 및 성능 모니터링 도구입니다. 클라이언트 측 JavaScript 오류부터 서버 측 Node.js 오류까지 통합적으로 관리할 수 있습니다.
    • 장점: 상세한 스택 트레이스, 사용자 컨텍스트, 발생 빈도, 영향도 등을 제공하여 오류 진단 및 우선순위 결정에 매우 유용합니다. Next.js와의 통합이 용이합니다.
    • 연동 방법: Sentry SDK를 설치하고, Next.js 설정 파일(next.config.js)에 Sentry 설정을 추가합니다. 클라이언트 측과 서버 측 모두에서 오류를 캡처하도록 설정합니다.
  • Datadog, New Relic, Grafana + Prometheus
    • 용도: 시스템 전체의 메트릭(CPU 사용량, 메모리, 네트워크, 응답 시간 등)을 수집하고 시각화하여 대시보드를 구축하며, 알림 시스템을 통해 이상 징후를 감지합니다.
    • 장점: 인프라 전체에 대한 포괄적인 가시성을 제공하여 복잡한 분산 시스템의 문제 해결에 필수적입니다.
    • 연동 방법: 각 도구의 에이전트나 SDK를 서버 환경에 설치하고, Next.js 애플리케이션에서 커스텀 메트릭을 전송하도록 설정합니다.

로깅 서비스

로깅 서비스 (Log Management System)는 대량의 로그를 효율적으로 수집, 저장, 검색, 분석하기 위한 시스템입니다.

  • ELK Stack (Elasticsearch, Logstash, Kibana)
    • 용도: 오픈 소스 기반의 강력한 로그 관리 솔루션입니다. Logstash로 로그를 수집하고, Elasticsearch에 저장하며, Kibana로 시각화하고 검색합니다.
    • 장점: 유연하고 확장성이 뛰어나며, 커스텀 대시보드와 강력한 검색 기능을 제공합니다.
  • Datadog Logs, Splunk, Sumo Logic
    • 용도: 클라우드 기반의 통합 로깅 및 분석 서비스입니다.
    • 장점: 설정 및 관리가 용이하며, APM, 메트릭 모니터링과 통합되어 엔드-투-엔드 가시성을 제공합니다.

효과적인 로깅 및 모니터링 전략

효과적인 운영은 로그를 많이 남기는 것이 아니라 레벨, 컨텍스트, 알림, 보존 기준을 함께 정하는 일입니다.

모니터링은 로그, 메트릭, 알림, 보존 정책을 함께 설계한다

로그를 많이 남기는 것만으로는 부족하다. 어떤 값이 문제 신호이고 언제 사람을 깨울지까지 정해야 운영 도구가 된다.

전략보는 값운영 기준주의점
로그 레벨debug, info, warn, error프로덕션은 info 이상, error는 즉시 추적debug 남발은 비용과 노이즈 증가
구조화 로그JSON 필드, requestId, user hash검색·집계 가능한 key/value 유지개인정보 원문 저장 금지
메트릭latency, error rate, throughputSLO나 임계치와 연결평균만 보면 꼬리 지연을 놓침
알림5xx spike, timeout, queue length사용자 영향이 있을 때 알림너무 잦은 알림은 무시됨
보존 정책원본 로그, 집계 로그, 감사 로그디버깅 기간과 규정 요구를 분리무기한 보존은 비용·보안 부담
  • 로그 레벨 활용: 개발/디버그 시에는 debug, info 레벨을 사용하고, 프로덕션에서는 info 이상(주로 warn, error)만 기록하여 로그 볼륨을 관리합니다.
  • 구조화된 로그: JSON과 같은 구조화된 포맷으로 로그를 기록하여 로그 분석 도구에서 쉽게 파싱하고 검색할 수 있도록 합니다.
  • 컨텍스트 정보 포함: 요청 ID, 사용자 ID, 트랜잭션 ID 등 관련 컨텍스트 정보를 로그에 포함하여 특정 요청의 전체 흐름을 추적할 수 있도록 합니다.
  • 경고 및 알림 설정: 중요한 오류나 임계치 초과(예: CPU 사용량 급증, 에러율 증가) 시 Slack, 이메일 등으로 알림을 받도록 설정하여 문제에 즉시 대응할 수 있도록 합니다.
  • 로그 보존 정책: 법적 요구사항이나 디버깅 필요성에 따라 로그 보존 기간을 설정합니다.
  • 성능 영향 고려: 로깅 자체가 애플리케이션 성능에 오버헤드를 주지 않도록 주의합니다. 특히 동기식 파일 I/O는 피하고 비동기 로깅을 사용합니다.

서버 사이드 로깅과 모니터링은 Next.js 애플리케이션의 안정성과 신뢰성을 보장하는 데 필수적인 요소입니다.

개발 초기부터 체계적인 로깅 전략을 수립하고, 적절한 모니터링 도구를 활용하여 애플리케이션의 건강 상태를 지속적으로 확인하는 것이 중요합니다.

이를 통해 잠재적인 문제를 사전에 감지하고, 발생한 문제를 신속하게 해결하여 사용자에게 끊김 없는 서비스를 제공할 수 있습니다.


서버 사이드 로깅과 모니터링은 다음 다이어그램처럼 요청 흐름, 실패 맥락, 알림 기준을 함께 설계해야 합니다.

요청 흐름, 실패 맥락, 알림 기준을 같은 ID로 묶는다

운영 중에는 한 요청이 브라우저, 서버, DB, 외부 API를 지나간 흔적을 같은 기준으로 이어 읽어야 한다.

흐름 단계기록할 맥락연결되는 도구대응 기준
브라우저 요청path, method, requestId headerNetwork, RUM사용자 체감 지연 확인
Next.js 서버 처리route handler, action, status, durationVercel Logs, logger500 또는 긴 duration 조사
DB/외부 APIquery name, upstream, retry, timeoutAPM, DB slow log병목 위치와 재시도 정책 확인
집계·대시보드error rate, p95 latency, trafficGrafana, Datadog, New Relic평소 기준선 대비 변화 확인
알림·회고incident id, impact, fix versionSlack, Pager, issue tracker재발 방지 항목으로 닫기

서버 사이드 로깅 및 모니터링의 판단 흐름을 화면 결과, 서버 비용, 운영 신호 기준으로 다시 묶었습니다.

화면 결과, 서버 비용, 운영 신호를 함께 봐야 장애 원인이 좁혀진다

사용자가 본 현상만으로는 원인이 부족하다. 화면, 로그, 비용, 알림 신호를 묶으면 어디부터 볼지 결정된다.

신호먼저 볼 증거의미다음 조치
화면 500/빈 화면Network status, server error log렌더링 또는 API 처리 실패requestId로 stack trace 검색
느린 응답duration, p95, slow queryDB, 외부 API, 서버 연산 병목구간별 latency를 분해
사용량 급증traffic, function invocation, bandwidth트래픽 증가 또는 반복 호출캐시, rate limit, 배치 작업 확인
특정 사용자 실패user hash, tenant, feature flag권한, 데이터 상태, 플래그 문제영향 범위와 재현 데이터 분리
알림 반복alert history, error budget일시적 오류가 아니라 운영 기준 초과incident로 묶고 임계치 재검토

아래 다이어그램은 Winston과 Pino, Vercel Logs, 외부 APM, 로깅 서비스가 서버 문제 추적에 연결되는 방식을 보여줍니다.

Winston/Pino, Vercel Logs, APM, 로그 서비스는 서로 다른 관측 층을 맡는다

하나의 도구로 모든 문제를 보려 하기보다 로그 생성, 배포 로그, 성능 추적, 장기 검색의 역할을 나눠 잡는다.

도구강점붙일 위치좋은 사용 기준
console.log가장 빠른 로컬 확인개발 중 route handler, server action임시 확인 후 구조화 로그로 정리
Winston/Pino레벨, 포맷, transport 제어공통 logger 모듈JSON 로그와 requestId 기본 포함
Vercel Logs배포별 서버리스 실행 로그 확인Vercel Runtime/Edge프로덕션 첫 확인 지점으로 사용
Sentry/APM오류 그룹화, trace, 영향도Next.js SDK, server/client boundary사용자 영향과 성능 trace 연결
로그 서비스대량 로그 검색, 보존, 대시보드Datadog, ELK, Splunk 등검색 필드와 보존 정책을 먼저 설계

결국 서버 사이드 관측은 재현 단서, 운영 지표, 수정 후 확인 기준을 같은 요청 흐름 안에서 연결하는 작업입니다.