본문 바로가기
BE/Node

Nest.js(5)

by Chars4785 2022. 7. 2.

로깅 - 애플리케이션의 동작을 기록한다

내장 Logger클래스는 @nest/common 패키지로 제공됩니다. 로깅 옵션을 조절하면 다음과 같이 로깅 시스템의 동작을 제어할 수 있습니다.

  • 로깅 비활성화
  • 로그 레벨 지정 - log, error, warn, debug, verbose
  • 로거의 타임스탬프 재정의. ex) 날짜를 ISO8601 형식으로 변경
  • 기본 로거를 재정의(오버라이딩)
  • 기본 로거를 확장해서 커스텀 로거를 작성
  • 의존성 주입을 통해 손쉽게 로거를 주입하거나 테스트 모듈로 제공
  • 외부 로거 winston

로거의 필요한 기능

- 서비스를 상용 수준으로 운용하기 위해서는 로그를 콘솔에만 출력하는 게 아니라 파일에 저장

- 중요한 로그는 데이터베이스에 저장을 해서 쉽게 검색할 수 있도록 해야 합니다.

- 로그 필터와 추적을 쉽게 해주는 다른 서비스로 로그를 전송을 하기도 합니다.

- 내장 로거 사용하면 힘듬 그래서 외장 로거 사용 ( nest-winston )

내장 로거

내장 로거의 인스턴스는 로그를 남기고자 하는 부분에서 직접 생성하여 사용할 수 있습니다. 모든 로그 레벨의 로그를 출력해 봅시다.

import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class AppService {
  private readonly logger = new Logger(AppService.name);

  getHello(): string {
    this.logger.error('level: error');
    this.logger.warn('level: warn');
    this.logger.log('level: log');
    this.logger.verbose('level: verbose');
    this.logger.debug('level: debug');

    return 'Hello World!';
  }
}

설정한 컨텍스트가 AppService로 함께 출력되고 있습니다. 로그 파일을 분석할 때 특정 컨텍스트에서 발생한 로그만 필터링 하고자 할 때 사용할 수 있습니다.

로그 비활성화

 false로 지정하면 로그가 출력되지 않습니다.

const app = await NestFactory.create(AppModule, {
  logger: false,
});
await app.listen(3000);

로그 레벨 지정

일반적으로 프로덕션 환경에서는 debug 로그가 남지 않도록 하는 게 좋습니다.디버그 로그는 테스트 과정에서 디버깅용으로 객체가 가지고 있는 세부 데이터까지 남기는 경우가 많습니다. 

- 개인정보 때문에 제외

- 로그 파일의 사이즈 줄이기 위한 목적

운영 환경에 따른 로그

const app = await NestFactory.create(AppModule, {
    logger: process.env.NODE_ENV === 'production' 
    ? ['error', 'warn', 'log']
    : ['error', 'warn', 'log', 'verbose', 'debug']
});

💡 만약 로그레벨을 하나만 설정한다면 해당 로그레벨보다 레벨이 낮은 레벨의 로그도 모두 함께 출력됩니다.

따라서 debug로만 설정한다면 모든 로그가 출력됩니다. 로그레벨의 정의는 Nest 소스코드에서 확인할 수 있습니다.

const LOG_LEVEL_VALUES: Record<LogLevel, number> = {
  debug: 0,
  verbose: 1,
  log: 2,
  warn: 3,
  error: 4,
};

커스텀 로거

@nestjs/common 패키지의 LoggerService 인터페이스를 구현해야 합니다.

export interface LoggerService {
  log(message: any, ...optionalParams: any[]): any;
  error(message: any, ...optionalParams: any[]): any;
  warn(message: any, ...optionalParams: any[]): any;
  debug?(message: any, ...optionalParams: any[]): any;
  verbose?(message: any, ...optionalParams: any[]): any;
    setLogLevels?(levels: LogLevel[]): any;
}

ConsoleLogger를 상속받으면 더 낫습니다.

export class MyLogger extends ConsoleLogger {
  error(message: any, stack?: string, context?: string) {
    super.error.apply(this, arguments);
    this.doSomething();
  }

  private doSomething() {
    // 여기에 로깅에 관련된 부가 로직을 추가합니다.
    // ex. DB에 저장    
  }

  ...
}

커스텀 로거 주입해서 사용하기

import { Module } from '@nestjs/common';
import { MyLogger } from './my-logger.service';

@Module({
  providers: [MyLogger],
  exports: [MyLogger],
})
export class LoggerModule { }
import { LoggerModule } from './logging/logger.module';

@Module({
  imports: [LoggerModule],
  ...
})
export class AppModule { }

이제 MyLogger 프로바이더를 주입받아 사용합니다.

커스텀 로거를 전역으로 사용하기

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useLogger(app.get(MyLogger));
  await app.listen(3000);
}

외부 로거 사용하기

상용 프로젝트에는 위와 같은 커스텀 로거를 매우 정교하게 다듬어 사용해야 할 것입니다. 하지만 NodeJs에는 이미 훌륭한 로깅 라이브러리인 winston이 있습니다. 나아가 winston을 Nest의 모듈로 만들어 놓은 nest-winston 패키지가 존재합니다. 유저 서비스에 nest-winston을 이용하여 로깅 기능을 구현해 보겠습니다.

nest-winston 적용

https://wikidocs.net/158644

 

11.3.1 nest-winston 적용

nest-winston 라이브러리를 이용해서 우리가 만들고 있는 서비스에 로깅 기능을 구현하도록 하겠습니다. nest-winston은 세가지 방식으로 적용할 수 있습니다. ...

wikidocs.net

예외 필터

예외가 발생했을 때 에러로그와 콜스택을 남겨 디버깅에 사용할 수 있도록 한다고 하면, 에러처리기를 따로 만들어 한 곳에서 공통으로 처리하도록 해야 합니다.

예외 처리

 

'BE > Node' 카테고리의 다른 글

DTO vs Entity  (1) 2022.07.28
Nest 맵  (0) 2022.07.28
Nest.js(4)  (0) 2022.06.29
관점 지향 프로그래밍(AOP)  (0) 2022.06.24
Nest.js(2)  (0) 2022.06.23

댓글