Sentry 도입하여 예외, 에러, 이슈 로깅

NestJS 애플리케이션에 Sentry 도입 및 AWS Elastic Beanstalk 환경 모니터링 가이드

AWS Elastic Beanstalk에 NestJS 기반 서버를 배포한 환경에서, Sentry(SaaS 버전)를 활용하여 애플리케이션의 오류와 이벤트를 모니터링하는 방법을 소개합니다. Sentry는 실행 중 발생하는 예외를 중앙에서 추적하고, 특정 비즈니스 이벤트나 보안 이상 행위를 감시하여 개발자가 신속하게 대응할 수 있도록 도와주는 도구입니다. 이 가이드에서는 다음과 같은 항목을 중점적으로 다룹니다:

아래에 NestJS에서 Sentry SDK를 설정하고, 글로벌 인터셉터와 커스텀 로직을 통해 위 시나리오들을 모니터링하는 방법을 단계별로 설명합니다.

Sentry SDK 설치 및 초기 설정

먼저 NestJS 프로젝트에 Sentry를 사용하기 위한 SDK를 설치하고 초기화합니다. Sentry Node SDK를 사용하며, 환경 변수로 민감한 정보(DSN 등)를 관리합니다.

  1. 패키지 설치: Sentry Node SDK를 프로젝트에 추가합니다. 터미널에서 다음 명령을 실행하세요:

    npm install @sentry/node
    

    (참고로 성능 모니터링까지 활용하려면 @sentry/profiling-node 등 추가 패키지도 설치할 수 있습니다.)

  2. Sentry DSN 준비: Sentry 웹 사이트에서 프로젝트를 생성하고 DSN(데이터 소스 이름)을 발급받습니다. DSN은 Sentry 프로젝트에 이벤트를 전송하기 위한 고유 URL이며, 노출되지 않도록 해야 합니다. AWS Elastic Beanstalk 환경 설정 또는 .env 파일에 다음과 같은 키를 추가합니다:

    # Elastic Beanstalk 환경 변수 또는 .env 파일 예시
    SENTRY_DSN=<Your Sentry DSN URL>
    SENTRY_ENVIRONMENT=production        # 현재 배포 환경 이름 (예: production, staging 등)
    SENTRY_RELEASE=myapp@1.0.0          # 애플리케이션 릴리스 버전 (선택 사항)
    
    • SENTRY_DSN: Sentry 프로젝트의 DSN URL을 설정합니다. (예: https://<key>@o<org>.ingest.sentry.io/<project-id> 형태)
    • SENTRY_ENVIRONMENT: 이벤트를 구분할 환경 이름을 지정합니다. 주로 production, staging 등을 사용하며 Sentry 대시보드에서 환경별로 이슈를 필터링할 수 있습니다.
    • SENTRY_RELEASE: 현재 배포된 애플리케이션의 버전이나 릴리스 식별자를 지정합니다. 예를 들어 패키지 버전이나 git 커밋 SHA 등을 사용할 수 있으며, 설정하면 Sentry에서 릴리스별 이슈 트래킹 및 배포 추적이 가능합니다.
  3. Sentry 초기화: 애플리케이션 시작 시점에 Sentry를 초기화해야 합니다. NestJS에서는 main.ts에서 애플리케이션을 생성하기 전에 초기화 코드를 실행하는 것이 바람직합니다. 다음은 main.ts의 예시입니다.

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import * as Sentry from '@sentry/node';
    
    async function bootstrap() {
      // Sentry 초기화
      Sentry.init({
        dsn: process.env.SENTRY_DSN,
        environment: process.env.SENTRY_ENVIRONMENT || 'production',
        release: process.env.SENTRY_RELEASE,  // e.g. "myapp@1.0.0"
        tracesSampleRate: 0.0,  // 성능 모니터링 비활성화 (필요 시 0.1~1.0으로 조정)
      });
      // ⚠️ Sentry.init()는 앱의 다른 모듈보다 **가장 먼저** 호출하여야 전역 예외를漏れ없이 포착합니다 ([Sentry | NestJS - A progressive Node.js framework](https://docs.nestjs.com/recipes/sentry#:~:text=%2F%2F%20Ensure%20to%20call%20this,)).
    
      const app = await NestFactory.create(AppModule);
      // ... (글로벌 미들웨어 등 설정 가능)
      await app.listen(3000);
    }
    bootstrap();
    

    위 코드에서 Sentry.init()에 DSN과 환경 등의 설정을 전달합니다. tracesSampleRate는 성능 추적을 위한 설정인데, 여기서는 우선 0으로 두어 비활성화하고 추후 필요에 따라 조정할 수 있습니다. Sentry.init 호출은 가능한 한 다른 모듈을 import하거나 애플리케이션 로직이 실행되기 전에 호출하여야 합니다. 이렇게 해야 Sentry가 애플리케이션 전역에서 발생하는 오류를 빠뜨리지 않고 잡아낼 수 있습니다 (Sentry | NestJS - A progressive Node.js framework).

    Sentry 초기화가 완료되면, 이후에 발생하는 예외나 명시적으로 전송하는 이벤트들이 Sentry로 보고됩니다.

전역 예외 처리 및 처리되지 않은 오류 추적

일반적으로 NestJS 애플리케이션에서 예상하지 못한 오류(uncaught exception)가 발생하면, 해당 요청에 대한 처리가 중단되고 NestJS가 기본 에러 응답을 보냅니다. AWS Elastic Beanstalk 환경에서는 이런 오류가 애플리케이션 로그(예: CloudWatch)로 남지만, 이를 일일이 확인하기 어렵고 누락될 수도 있습니다. Sentry를 도입하면 이런 전역 예외들을 자동으로 수집하여 대시보드에서 한눈에 모니터링할 수 있습니다 (Monitoring your NestJS application with Sentry — Soshace).

NestJS 앱에서 발생한 InternalServerErrorException이 Sentry Issues 목록에 수집된 모습. Sentry는 발생한 오류들을 모아서 보여주고, 스택 트레이스 및 컨텍스트 정보를 제공하여 개발자가 원인을 파악할 수 있도록 돕습니다.

글로벌 예외 추적을 구현하는 한 가지 방법은 NestJS의 **인터셉터(Interceptor)**를 활용하는 것입니다. 인터셉터는 모든 요청을 가로채어 전후 처리를 할 수 있는 구성요소로, 여기서는 전역 인터셉터를 만들어 각 요청 처리 중 발생하는 예외를 잡아 Sentry로 전송하도록 합니다.

우선 새로운 인터셉터를 작성합니다. 아래는 SentryInterceptor라는 이름의 인터셉터 구현 예시입니다:

// sentry.interceptor.ts
import {
  Injectable, NestInterceptor, ExecutionContext, CallHandler,
  HttpException, UnauthorizedException, HttpStatus
} from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import * as Sentry from '@sentry/node';

@Injectable()
export class SentryInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    const http = context.switchToHttp();
    const req = http.getRequest();
    const { method, url } = req;

    return next.handle().pipe(
      // 1) 각 요청 완료 후 실행되는 부분 (정상 응답의 후처리)
      tap(() => {
        const elapsed = Date.now() - now;
        if (elapsed > 1000) {  // 예: 1초를 초과하는 느린 요청 감지
          Sentry.captureMessage(
            `Slow Request [${elapsed}ms] ${method} ${url}`, 
            'info'
          );
        }
      }),
      // 2) 예외 발생 시 실행되는 부분
      catchError((error) => {
        // Sentry에 예외 전송
        Sentry.captureException(error);
        return throwError(() => error);  // 예외를 다시 던져 다음 처리(기본 에러 응답)를 진행
      }),
    );
  }
}

위 인터셉터는 next.handle()로 실제 라우트 핸들러를 실행하고, 그 반환 Observable에 대해 두 가지 파이프라인을 설정합니다:

SentryInterceptor를 **전역(Global)**으로 적용하면, 모든 요청에서 발생하는 처리되지 않은 에러를 가로채 Sentry에 기록할 수 있습니다. 전역으로 등록하는 방법은 두 가지가 있습니다:

간단한 방법은 main.ts에서 설정하는 것입니다. 앞서 Sentry 초기화 후 아래와 같이 인터셉터를 등록합니다:

const app = await NestFactory.create(AppModule);
// ... Sentry.init(...) (이미 호출됨)
app.useGlobalInterceptors(new SentryInterceptor());
await app.listen(3000);

이렇게 하면 애플리케이션의 모든 요청에 대해 SentryInterceptor가 동작하여 에러를 포착하게 됩니다. 이제 서버에서 발생하는 예기치 않은 오류(throw된 예외로 인해 처리되지 못한 에러)는 Sentry 대시보드에서 확인할 수 있습니다. Sentry는 오류 발생 횟수나 추세를 모니터링하고, 이메일/슬랙 알림 등을 통해 개발자가 빠르게 인지할 수 있도록 해줍니다.

Note: NestJS의 HttpException (및 그 파생 클래스들)은 주로 클라이언트에 특정 응답을 보내기 위한 제어 흐름 용도로 사용되므로, Sentry에서는 기본 설정상 이러한 예외는 "에러"로 간주하지 않고 수집을 건너뜁니다 (Sentry | NestJS - A progressive Node.js framework). 예를 들어 BadRequestException이나 NotFoundException은 의도된 400 혹은 404 응답으로 처리되는 경우가 많습니다. 그러나 보안상의 이유로 401 Unauthorized429 Too Many Requests 같은 경우에는 Sentry에 남겨 모니터링하고 싶을 수 있습니다. 이런 경우 본 가이드처럼 수동으로 해당 예외를 선별하여 captureException 또는 captureMessage를 호출하면 Sentry에 기록할 수 있습니다.

사용자 정의 이벤트 Sentry 전송 (PaymentRecovered, RefundFailed 등)

실제 서비스 운영에서는 비즈니스 로직상의 중요한 사건이나 특정 상태를 추적해야 하는 경우가 있습니다. 예를 들어 "결제 복구 성공(PaymentRecovered)", "환불 처리 실패(RefundFailed)", "의심스러운 사용 행위 감지(AbuseAttempt)" 등의 이벤트는 비록 애플리케이션이 오류로 크래시난 것은 아니지만, 개발/운영 팀에서 주시해야 할 중요한 이벤트입니다. Sentry는 단순히 예외뿐만 아니라 이러한 사용자 정의 이벤트나 메시지도 전송하여 기록할 수 있습니다.

NestJS 코드 내에서 특정 조건이나 결과가 발생할 때 Sentry SDK의 함수를 호출하면 해당 이벤트를 Sentry에 남길 수 있습니다. 주요 사용 함수는 다음과 같습니다:

아래는 사용자 정의 이벤트를 보내는 코드 예시들입니다:

// 결제 복구 성공 시 (예: 결제 장애 복구 로직 내)
if (paymentRecovered) {
  Sentry.captureMessage(
    `PaymentRecovered: 결제ID ${paymentId} 복구 완료`,
    'info'
  );
}
// 환불 처리 실패 시 (예: 환불 서비스 로직 내)
if (!refundSuccess) {
  Sentry.captureMessage(
    `RefundFailed: 주문번호 ${orderId} 환불 실패 - 사유: ${failReason}`,
    'error'
  );
}
// 악용 시도 감지 시 (예: 특이 행동 패턴 탐지 로직 내)
if (isAbuseDetected) {
  Sentry.captureEvent({
    message: 'AbuseAttempt: 다수의 비인가 요청 탐지됨',
    level: 'warning',
    extra: { ip: clientIp, reason: 'Throttle limit exceeded' }
  });
}

위 코드들은 각각의 상황에서 Sentry로 이벤트를 전송합니다. PaymentRecovered 예시에서는 정보 차원의 이벤트로 분류하고 (info 레벨), RefundFailed는 문제가 발생한 시나리오이므로 error 레벨로 설정했습니다. AbuseAttempt 같은 보안 관련 이벤트는 경고 수준으로 남기고 (warning 레벨), extra 필드에 부가 정보를 담았습니다.

이렇게 전송된 이벤트들은 Sentry 대시보드에서 메시지 형태의 이슈로 나타나며, 일반 에러와 마찬가지로 타임라인에 기록되고 검색/필터링할 수 있습니다. 예를 들어 Sentry에서 "AbuseAttempt" 키워드로 검색하면 관련 경고 이벤트들을 모두 조회할 수 있습니다. 또한 tagsextra 정보를 활용하면 이벤트에 추가적인 맥락(context)을 부여할 수 있어 분석에 도움이 됩니다. (예: extrauserId, role 등을 담아 어떤 사용자가 발생시켰는지 파악 가능)

Tip: Sentry 이벤트에는 **태그(tags)**를 달아 분류할 수 있습니다. Sentry.captureEvent를 사용할 때 tags: { eventType: 'PaymentRecovered' }처럼 태그를 포함하면 Sentry UI에서 태그별 필터링이 가능합니다. 또한, scope.setContextscope.setExtra 등을 통해 이벤트 발생 시의 맥락 데이터를 설정해 둘 수도 있습니다. 이는 추후 해당 이슈를 분석할 때 유용한 부가 정보를 함께 확인할 수 있게 해줍니다.

시스템 이벤트 핸들러에서의 오류 추적

NestJS 애플리케이션은 HTTP 요청/응답 외에도 이벤트 기반으로 동작하는 부분이 있을 수 있습니다. 예를 들어 Cron 작업, 백그라운드 잡(queue), 또는 NestJS의 이벤트 기반 아키텍처(CQRS 패턴의 Events, EventEmitter2를 활용한 도메인 이벤트 등)를 사용하는 경우입니다. 이러한 시스템 수준 이벤트 처리 중에 발생하는 오류도 Sentry로 추적하는 것이 중요합니다.

전역 인터셉터는 HTTP 요청 흐름에서 발생하는 오류를 포착하지만, HTTP 컨텍스트 바깥에서 발생하는 예외(예: 이벤트 핸들러 내부)는 해당하지 않을 수 있습니다. 따라서 이벤트 핸들러 내부에서 별도로 Sentry 보고를 해야 합니다.

예를 들어, NestJS의 CQRS 모듈에서 이벤트를 발행하고 처리한다고 가정해보겠습니다. PaymentRecoveredEventRefundFailedEvent라는 이벤트 클래스가 있고, 이를 처리하는 이벤트 핸들러가 다음과 같이 있을 수 있습니다:

import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import * as Sentry from '@sentry/node';

@EventsHandler(PaymentRecoveredEvent)
export class PaymentRecoveredHandler implements IEventHandler<PaymentRecoveredEvent> {
  async handle(event: PaymentRecoveredEvent) {
    try {
      // 이벤트 처리 로직 (예: 후속 작업 수행)
      await this.billingService.clearPendingFlag(event.paymentId);
      // ... 기타 처리
    } catch (error) {
      // 이벤트 처리 중 예외 발생 시 Sentry 보고
      Sentry.captureException(error);
      throw error;  // 예외를 다시 던져 상위 프로세스에도 인지되도록 (필요 시)
    }
  }
}

PaymentRecoveredHandlerPaymentRecoveredEvent 처리 중 예외가 발생하면 Sentry.captureException(error)를 호출하여 Sentry에 오류를 남깁니다. 이처럼 각 이벤트 핸들러 내부의 try-catch 블록에서 Sentry로 예외를 전송하는 패턴을 사용합니다. 이벤트 처리 로직에 따라 오류 발생 시 적절히 복구하거나 재시도를 할 수도 있지만, Sentry에 기록해 두면 해당 오류 이벤트의 발생 빈도나 패턴을 추적할 수 있습니다.

또 다른 예로, RefundFailedEvent를 받아 일부 보정 작업을 수행하는 이벤트 핸들러를 생각해보겠습니다. 이 이벤트 자체는 "환불 실패"라는 사건을 나타내므로, 처리 로직이 성공적으로 끝나더라도 운영 상 주목할 만한 정보입니다. 따라서 오류 여부와 관계없이 이벤트 발생 자체를 Sentry에 남길 수도 있습니다:

@EventsHandler(RefundFailedEvent)
export class RefundFailedHandler implements IEventHandler<RefundFailedEvent> {
  handle(event: RefundFailedEvent) {
    // 환불 실패 이벤트 발생: 상세 정보를 Sentry에 로그로 남김
    Sentry.captureMessage(
      `RefundFailedEvent: 주문 ${event.orderId}, 이유: ${event.reason}`,
      'error'
    );
    // 추가 처리 로직...
  }
}

위와 같이 이벤트 발생 자체를 하나의 이슈로 기록하면, 애플리케이션에서 실패한 환불 건들을 Sentry 대시보드에서 모니터링할 수 있습니다. (예: 환불 실패가 특정 결제수단이나 특정 기간에 집중되는지 등의 분석 가능)

정리하면, HTTP 요청 외부의 비동기 작업이나 이벤트 처리 중 발생하는 오류는 개발자가 직접 Sentry에 전송하도록 구현해야 합니다. NestJS의 이벤트 처리 구조(CQRS, 이벤트 에미터, 스케줄러 등)에 Sentry를 수동으로 훅인(hook in)하여, 운영 중 일어나는 다양한 문제 상황을 빠짐없이 수집하도록 합니다.

보안 관련 이상 행위 탐지 및 로그 전송

보안상의 이상 징후(Unauthorized access 시도나 Rate limit 초과 등)는 흔히 애플리케이션이 고의로 발생시키는 예외이지만, 이를 모니터링하면 공격 징후를 파악하거나 잘못된 사용 패턴을 분석하는 데 도움이 됩니다. Sentry를 활용하여 이러한 보안 이벤트도 추적할 수 있습니다.

대표적인 예로 비인가 접근과도한 요청 상황을 들 수 있습니다:

이러한 상황을 Sentry에 기록하는 방법은 두 가지입니다:

  1. 인증/Throttle 가드에서 직접 Sentry 호출
  2. 글로벌 인터셉터나 예외 필터를 통해 해당 예외 포착

첫 번째 방법은 NestJS의 Guard를 커스터마이징하는 것입니다. 예를 들어 JWT 인증 Guard를 상속하여 인증 실패 시 Sentry에 로그를 남기도록 오버라이드할 수 있습니다:

import { ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import * as Sentry from '@sentry/node';

export class JwtAuthGuard extends AuthGuard('jwt') {
  handleRequest(err: any, user: any, info: any, context: ExecutionContext) {
    // 인증 실패한 경우
    if (!user) {
      const req = context.switchToHttp().getRequest();
      const ip = req.ip;
      Sentry.captureMessage(
        `Unauthorized access attempt - IP: ${ip}, Reason: ${info?.message || err?.message}`,
        'warning'
      );
      throw err || new UnauthorizedException();
    }
    // 인증 성공한 경우
    return user;
  }
}

JwtAuthGuard에서는 handleRequest를 오버라이드하여 인증에 실패한 경우 Sentry에 경고 메시지를 보내도록 했습니다. 이렇게 하면 토큰 만료/유효하지 않음 등으로 인증이 거부될 때마다 해당 IP나 사유를 Sentry에서 기록하게 됩니다. (물론 너무 잦은 시도는 Sentry 이슈를 다수 생성할 수 있으므로, 필요에 따라 샘플링하거나 조건을 두어 중요한 경우에만 남기는 것이 좋습니다.)

두 번째 방법은 앞서 구현한 SentryInterceptor를 활용하는 것입니다. 인터셉터의 catchError 내부에서 예외 종류를 검사하여 401이나 429일 때 별도의 처리를 해줄 수 있습니다. 예를 들어, SentryInterceptorcatchError 부분을 다음처럼 확장할 수 있습니다:

catchError((error) => {
  // 401/429 등 보안 관련 예외를 선별
  if (error instanceof UnauthorizedException) {
    const req = http.getRequest();
    Sentry.captureMessage(
      `Unauthorized access: ${req.ip} -> ${req.method} ${req.url}`,
      'warning'
    );
  }
  if (error.getStatus && error.getStatus() === HttpStatus.TOO_MANY_REQUESTS) {
    const req = http.getRequest();
    Sentry.captureMessage(
      `Too Many Requests: IP ${req.ip} - ${req.method} ${req.url}`,
      'warning'
    );
  }
  // 공통 예외 처리
  Sentry.captureException(error);
  return throwError(() => error);
})

위 코드는 UnauthorizedException인 경우와 HTTP 상태 코드 429인 경우(TooManyRequestsException)를 체크하여, 각기 다른 메시지를 Sentry에 남기는 예시입니다. IP, HTTP 메서드, URL 등의 정보를 포함시켜 어떤 요청에서 문제가 발생했는지 파악하도록 했습니다. 이 경우에도 captureException을 통해 Sentry에 스택트레이스를 남기지만, 401/429와 같이 의도적으로 throw된 예외의 경우 메시지만으로도 충분한 정보를 줄 수 있어 captureMessage를 함께 사용했습니다.

주의: Guard 단계에서 예외가 발생하면 인터셉터까지 도달하지 않을 수 있으므로, 가능하면 Guard 내부에서 바로 Sentry 호출을 하는 것이 확실합니다. 글로벌 예외 필터(ExceptionFilter)를 사용해도 되지만, NestJS의 기본 예외 흐름과 충돌하지 않도록 주의해야 합니다.

이런 보안 이벤트를 Sentry로 수집하면, 개발자는 Sentry 대시보드나 알림을 통해 비정상적인 접근 시도를 인지할 수 있습니다. 예를 들어, 짧은 시간 내 429 에러가 폭증하면 DDoS 시도나 버그로 인한 과잉 호출을 의심하여 대응할 수 있고, 반복적인 401 발생은 잘못된 API 사용 또는 공격 시도를 나타낼 수 있습니다. 이는 AWS Elastic Beanstalk의 로그를 통해서도 감지할 수 있지만, Sentry를 통해 실시간 경고와 함께 자세한 발생 정보를 바로 얻을 수 있다는 장점이 있습니다.

NestJS Interceptor를 활용한 전역 요청 모니터링

앞서 구현한 SentryInterceptor는 전역으로 모든 HTTP 요청을 가로채어 오류를 처리했습니다. 이 인터셉터를 조금 확장하면 요청에 대한 종합적인 모니터링 도구로 활용할 수 있습니다. 이미 코드에서 사용한 것처럼, tap() 연산자를 이용하여 각 요청의 처리 시간을 측정하고 임계치를 초과하는 경우 Sentry로 보고하는 식으로 응용할 수 있습니다.

또 다른 모니터링 예로, 요청별 사용자 정보나 파라미터를 Sentry에 남겨두는 것을 고려할 수 있습니다. Sentry는 이벤트당 User 컨텍스트를 설정할 수 있어서, 오류 발생 시 어떤 사용자의 요청이었는지 파악할 수 있습니다. 글로벌 인터셉터에서 인증된 사용자의 정보를 Sentry Scope에 설정해두면 이후 발생하는 에러나 이벤트에 자동으로 첨부됩니다:

// 인터셉터 내 (요청 시작 시)
const user = req.user;
if (user) {
  Sentry.setUser({ id: user.id, username: user.username, email: user.email });
}
Sentry.setExtra('requestId', req.headers['x-request-id'] || 'N/A');

위와 같이 Sentry.setUser()를 통해 현재 요청자의 식별자를 설정하고, setExtra 등을 사용해 요청 ID와 같은 부가 정보를 설정할 수 있습니다. 이렇게 하면 동일한 사용자에게 반복적으로 발생하는 오류를 추적하거나, 특정 요청 ID로 로깅 시스템과 연계하는 것이 쉬워집니다. (Sentry 대시보드의 이슈 상세에서 해당 user나 extra 정보를 확인할 수 있습니다.)

또한 Sentry에는 **Breadcrumb(빵부스러기)**라는 기능이 있어, 이벤트가 발생하기 전의 로그들을 기록해둘 수 있습니다. 인터셉터를 활용하여 각 요청 시작 시점에 breadcrumb을 남기거나, 중요한 서브 작업마다 Sentry.addBreadcrumb()을 호출해두면, 이후 오류 발생 시 그 전에 어떤 일들이 일어났는지 흐름을 파악하는 데 도움이 됩니다. 예를 들어:

Sentry.addBreadcrumb({
  category: 'request',
  message: `${method} ${url} 요청 수신`,
  level: 'info'
});

를 요청 진입 시 실행하면, 이후 오류가 발생했을 때 이 breadcrumb이 에러 이벤트의 부가정보로 포함되어 Sentry에서 확인할 수 있습니다. (단, Node 환경에서는 각 요청별 context 분리가 필요하므로, Sentry Node SDK가 제공하는 AsyncLocalStorage 기반 자동 분리가 활성화된 경우에 유효합니다. 최신 @sentry/node SDK에서는 기본적으로 이러한 컨텍스트 분리를 지원합니다.)

정리하면, Interceptor를 활용한 요청 모니터링은 다음과 같은 이점을 제공합니다:

이러한 모니터링 정보들은 일반 로그에도 남길 수 있지만, Sentry에 모아두면 오류와 같은 맥락에서 함께 관리되고, Sentry UI 상에서 한눈에 관련 정보를 볼 수 있다는 장점이 있습니다.

Elastic Beanstalk 로그 모니터링 대비 Sentry 활용의 장점

AWS Elastic Beanstalk 환경에서는 애플리케이션 로그를 보기 위해 EC2 인스턴스에 접속하거나, EB CLI/콘솔을 통해 로그를 수집해야 합니다. 이러한 방식은 다음과 같은 한계가 있습니다:

Sentry를 도입하면 위와 같은 부분에서 많은 개선이 이루어집니다:

요약하면, Elastic Beanstalk의 원시 로그는 기본적인 모니터링 수단이지만, Sentry를 통해 보다 구조화되고 지능적인 모니터링을 구현함으로써 개발 생산성과 서비스 안정성을 높일 수 있습니다. 특히 사용자에게 미치는 영향이 큰 에러나 보안 이상 징후를 조기에 인지하여 대응하는 데 있어 Sentry는 강력한 도구가 됩니다.

환경 변수 및 설정 관리 요약

마지막으로 Sentry 통합과 관련된 환경 설정 요점을 정리합니다:

Elastic Beanstalk에서는 이러한 환경변수를 EB 콘솔의 Configuration > Software 설정에서 추가하거나, .ebextensions 설정 파일을 통해 세팅할 수 있습니다. 배포된 애플리케이션 인스턴스에서 process.env.SENTRY_DSN으로 접근하면 설정된 값이 나오는지 확인하세요.

마지막으로, Sentry SDK 초기화나 인터셉터 등록 코드는 운영 환경에서만 적용하고, 로컬 개발 환경 등에서는 DSN을 비워두거나(SENTRY_DSN 미설정) 조건부로 활성화하는 것을 권장합니다. 이렇게 하면 개발 중에는 불필요한 Sentry 로그가 쌓이지 않으면서, 로컬에서는 콘솔 로그를 통해 디버깅하고 실제 운영 환경에서만 Sentry 모니터링을 사용할 수 있습니다.

결론

이상으로 NestJS 프로젝트에 Sentry를 통합하여 전역 예외, 커스텀 이벤트, 이벤트 처리 오류, 보안 이상징후 등을 감지하고 모니터링하는 실무 방법을 살펴보았습니다. Sentry 설정 초기화부터 글로벌 인터셉터 적용, 그리고 상황별로 Sentry에 이벤트를 보내는 다양한 예제 코드를 제시했으므로, 이를 토대로 자신의 프로젝트에 맞게 응용할 수 있습니다.

Sentry를 잘 활용하면 Elastic Beanstalk 환경에서 발생하는 여러 문제를 실시간으로 한 곳에서 추적할 수 있고, 장애나 이상 상황에 보다 빠르게 대응할 수 있습니다. 나아가 팀원들과 오류 정보를 공유하고, 누적된 데이터를 통해 소프트웨어의 안정성을 지속적으로 개선해나갈 수 있을 것입니다. NestJS의 강력한 미들웨어/인터셉터 체계와 Sentry의 모니터링 플랫폼을 결합하여 서비스 품질을 한층 향상시켜 보시기 바랍니다. 즐거운 디버깅과 안정적인 운영이 되시길 바랍니다!