icon

모니터링과 로깅 시스템 구축


 애플리케이션 모니터링과 로깅은 시스템의 건강 상태를 파악하고, 문제를 신속하게 진단하며, 성능을 최적화하는 데 필수적입니다.

 NestJS 애플리케이션에서 효과적인 모니터링과 로깅 시스템을 구축하면 운영 효율성이 크게 향상됩니다.

모니터링과 로깅의 이점

  1. 실시간 성능 모니터링
  2. 문제 조기 발견 및 신속한 대응
  3. 트렌드 분석을 통한 용량 계획
  4. 보안 위협 탐지
  5. 사용자 경험 개선

Prometheus와 Grafana 기반 메트릭

  1. 의존성 설치
npm install @nestjs/terminus prom-client
  1. HealthController 구현
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, HttpHealthIndicator } from '@nestjs/terminus';
 
@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private http: HttpHealthIndicator,
  ) {}
 
  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () => this.http.pingCheck('nestjs-docs', 'https://docs.nestjs.com'),
    ]);
  }
}
  1. Prometheus 메트릭 엔드포인트 설정
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { PrometheusModule } from '@nestjs/terminus';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(PrometheusModule.createMiddleware());
  await app.listen(3000);
}
bootstrap();
  1. Grafana 대시보드 설정 : Prometheus 데이터 소스 추가 및 대시보드 생성

ELK 스택을 이용한 로그 중앙화 및 분석

  1. winston 로거 설정
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
 
@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'combined.log' }),
      ],
    }),
  ],
})
export class AppModule {}
  1. Logstash 설정 (logstash.conf)
input {
  file {
    path => "/path/to/combined.log"
    start_position => "beginning"
  }
}
 
output {
  elasticsearch {
    hosts => ["localhost:9200"]
  }
}
  1. Kibana에서 인덱스 패턴 생성 및 대시보드 구성

분산 추적 시스템 통합

 Jaeger를 NestJS 마이크로서비스에 통합

  1. 의존성 설치
npm install @nestjs/opentelemetry @opentelemetry/instrumentation-http @opentelemetry/exporter-jaeger
  1. 추적 모듈 설정
import { Module } from '@nestjs/common';
import { OpenTelemetryModule } from '@nestjs/opentelemetry';
 
@Module({
  imports: [
    OpenTelemetryModule.forRoot({
      serviceName: 'my-service',
      exporter: {
        type: 'jaeger',
        options: {
          endpoint: 'http://localhost:14268/api/traces',
        },
      },
    }),
  ],
})
export class AppModule {}

클라우드 제공업체의 모니터링 서비스 적용

 AWS CloudWatch 활용

  1. 의존성 설치
npm install aws-sdk
  1. CloudWatch 로거 구현
import { CloudWatchLogs } from 'aws-sdk';
 
const cloudWatchLogs = new CloudWatchLogs();
 
async function logToCloudWatch(message: string, logGroupName: string, logStreamName: string) {
  await cloudWatchLogs.putLogEvents({
    logGroupName,
    logStreamName,
    logEvents: [{ message, timestamp: Date.now() }],
  }).promise();
}

APM 도구 통합

 New Relic APM 통합

  1. 의존성 설치
npm install newrelic
  1. 진입점 파일 (main.ts) 수정
import 'newrelic';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

 APM을 통해 얻을 수 있는 인사이트

  • 트랜잭션 성능 분석
  • 에러 추적 및 근본 원인 분석
  • 데이터베이스 쿼리 성능
  • 외부 서비스 의존성 모니터링

알림 시스템 구축

 Slack을 이용한 알림 시스템

  1. Slack 웹훅 URL 설정
  2. 알림 서비스 구현
import { Injectable } from '@nestjs/common';
import axios from 'axios';
 
@Injectable()
export class AlertService {
  private slackWebhookUrl = 'YOUR_SLACK_WEBHOOK_URL';
 
  async sendAlert(message: string) {
    await axios.post(this.slackWebhookUrl, { text: message });
  }
}
  1. 중요 이벤트에서 알림 트리거
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  constructor(private alertService: AlertService) {}
 
  async catch(exception: unknown, host: ArgumentsHost) {
    await this.alertService.sendAlert(`Error occurred: ${exception}`);
    // 추가적인 예외 처리 로직
  }
}

로그 레벨 관리 및 동적 설정

  1. 환경 변수를 통한 로그 레벨 설정
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
 
WinstonModule.forRoot({
  level: process.env.LOG_LEVEL || 'info',
  // 기타 설정
})
  1. API를 통한 동적 로그 레벨 변경
@Controller('logs')
export class LogController {
  constructor(private logger: Logger) {}
 
  @Post('level')
  setLogLevel(@Body() body: { level: string }) {
    this.logger.setLogLevel(body.level);
    return { message: `Log level set to ${body.level}` };
  }
}

Best Practices 및 주의사항

  1. 민감한 정보 로깅 주의 : 개인정보, 비밀번호 등 마스킹 처리
  2. 로그 보존 정책 수립 : 법적 요구사항 및 스토리지 비용 고려
  3. 구조화된 로깅 : JSON 형식 사용으로 분석 용이성 증대
  4. 상관관계 ID 사용 : 분산 시스템에서 요청 추적 용이
  5. 적절한 로그 레벨 사용 : INFO, WARN, ERROR 등 상황에 맞는 레벨 선택
  6. 정기적인 모니터링 대시보드 리뷰 : 트렌드 분석 및 이상 징후 조기 발견
  7. 알림 임계값 최적화 : 과도한 알림으로 인한 피로도 방지
  8. 성능 영향 최소화 : 로깅 작업이 애플리케이션 성능에 미치는 영향 고려
  9. 로그 롤링 및 압축 : 디스크 공간 관리 및 검색 성능 최적화
  10. 모니터링 및 로깅 시스템 자체의 모니터링 : 메타 모니터링 구현

 효과적인 모니터링과 로깅 시스템을 구축하는 것은 애플리케이션의 안정성, 성능, 그리고 운영 효율성을 크게 향상시킵니다.

 Prometheus와 Grafana를 활용한 메트릭 수집 및 시각화는 실시간 성능 모니터링을 가능하게 하며, 시스템의 병목 현상이나 이상 동작을 신속하게 감지할 수 있게 해줍니다.

 ELK 스택을 통한 로그 중앙화 및 분석은 분산된 시스템에서 발생하는 로그를 효과적으로 관리하고 분석할 수 있게 합니다.

 이를 통해 문제의 근본 원인을 빠르게 파악하고, 트렌드를 분석하여 선제적인 대응이 가능해집니다.

 분산 추적 시스템의 통합은 마이크로서비스 아키텍처에서 특히 중요합니다.

 Jaeger와 같은 도구를 사용하면 서비스 간 요청 흐름을 시각화하고, 성능 병목 지점을 식별할 수 있습니다.