[Nest.js] winston logger 사용하기

Woong·2022년 11월 25일
1

Nestjs

목록 보기
7/28

설치

  • winston 설치
    • npm i nest-winston winston
  • 파일로 남기기 위해선 winston-daily-rotate-file 추가 설치
    • npm i winston-daily-rotate-file

logger 설정

  • 개발/운영 환경에 따라 level 을 다르게 지정
    • .env 에서 NODE_ENV, APP_NAME, LOG_DIR 등 환경변수 설정하여 활용
    • AppModule 에서 정의해도 되지만, logger 를 위한 module을 만들고 import 하는 것이 개발 및 테스트하기 좋다.
import * as winston from 'winston';
import {
  utilities as nestWinstonModuleUtilities,
  WinstonModule,
} from 'nest-winston';
import * as winstonDaily from 'winston-daily-rotate-file'

@Module{(
  imports: [
    ConfigModule.forRoot({ isGlobal: true})
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          level: process.env.NODE_ENV === 'production' ? 'info' : 'silly',
          format: winston.format.combine(
            winston.format.timestamp(),
            nestWinstonModuleUtilities.format.nestLike(process.env.APP_NAME, { prettyPrint: true }),
          ),
        }),
        new winstonDaily ({
          level: process.env.NODE_ENV === 'production' ? 'info' : 'silly',
          format: winston.format.combine(
            winston.format.timestamp({
              format: 'YYYY-MM-DD HH:mm:ss',
            }),
            winston.format.printf(
              (info) =>
                `[${info.timestamp}] ${process.env.APP_NAME}.${info.level}: ${info.message}`,
            ),
          ),
          dirname: process.env.LOG_DIR
          filename: '%DATE%.log',
          datePattern: 'YYYY-MM-DD',
          zippedArchive: true,
          maxSize: '20m',
          maxFiles: '14d',
        }),
      ],
    }),
  ],
})
export class LoggerModule { }

logger 적용

  • Module 에서 import
@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    LoggerModule,
    ...
  ],
  ...
})
export class AppModule() {
  ...
}
  • Logger 주입
import { Logger } from 'winston';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
...

export class UsersController {
  constructor(
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) { }

  private printWinstonLog(dto) {
    console.log(this.logger.name);

    this.logger.error('error: ', dto);
    this.logger.warn('warn: ', dto);
    this.logger.info('info: ', dto);
    this.logger.http('http: ', dto);
    this.logger.verbose('verbose: ', dto);
    this.logger.debug('debug: ', dto);
    this.logger.silly('silly: ', dto);
  }

테스트시 주입

  • 생성자를 통해 winston 의 Logger 를 주입하기 때문에, 테스트코드에도 이를 반영해야 한다.

    1. Logger 를 mocking 하는 방법
describe(‘UserController’, () => {
  let userController: UserController

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [ConfigModule],
      providers: [
        ConfigService,
        { provide: WINSTON_MODULE_PROVIDER, useValue: {
            silly: jest.fn(),
            debug: jest.fn(),
            verbose: jest.fn(),
            http: jest.fn(),
            info: jest.fn(),
            warn: jest.fn(),
            error: jest.fn(),
            log: jest.fn()
          }, // winston logger 
          ...
      ],
      controllers: [
        UserController
      ]
    }).compile()

    userController = module.get<UserController>(UserController)
  })
  
it('should be defined', () => {
  expect(userController).toBeDefined()
})
    1. 정의한 Logger Module 을 import 하여 사용하는 방법
    • 이쪽이 훨씬 심플하다
describe(‘UserController’, () => {
  let userController: UserController

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [ConfigModule, LoggerModule],
      providers: [
        ConfigService,
        ...
      ],
      controllers: [
        UserController
      ]
    }).compile()

    userController = module.get<UserController>(UserController)
  })
  
it('should be defined', () => {
  expect(userController).toBeDefined()
})

reference

0개의 댓글