개발/Node & Javascript

Nest.js 탐험기 - logging을 winston과 함께 사용해보자.

말고기 2021. 2. 12. 16:22
728x90
반응형

개요

  • 이번 시간에는 logging을 적용해보려고 한다.
  • winston을 사용해보려고 한다.

Setup

우선 logging을 적용하기 위해 다음과 같이 설치해준다.

yarn add winston winston-daily-rotate-file;

winston

  • Node 진영의 대표적인 로깅 라이브러리이다.
  • 다양한 transport layer를 사용할 수 있고, 또한 custom하게 implementation이 가능하다.
  • winston-daily-rotate-file의 경우에는 logrotate를 설정하기 위해서 사용했다.

코드를 작성해보자!

1. configuration 등록

우선적으로 winston을 먼저 셋팅해두자.


import * as winston from 'winston';
import 'winston-daily-rotate-file';
import { Logger, format } from 'winston';
const { combine, timestamp, prettyPrint, colorize, errors, json } = format;

let logger: Logger;

const createLogger = () => {
  if (logger) {
    logger.error('Logger instance already defined. So ignore it.');
    return;
  }

  logger = winston.createLogger({
    level: process.env.NODE_ENV === 'production' ? 'warn' : 'info',
    format: combine(
      errors({ stack: true }), // <-- use errors format
      timestamp(),
      json(),
      ...(process.env.NODE_ENV !== 'production' ? [prettyPrint()] : []),
    ),
    defaultMeta: { service: 'pie' },
    transports: [],
  });

  if (process.env.NODE_ENV !== 'production') {
    logger.add(
      new winston.transports.Console({
        format: winston.format.combine(winston.format.colorize(), winston.format.simple()),
      }),
    );
  }

  // 절대로 production에 이 파일 넣으면 안됩니다. maxSize를 보세여!!
  if (process.env.NODE_ENV === 'production') {
    logger.add(
      new winston.transports.DailyRotateFile({
        level: 'error',
        filename: 'log/error-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '1k',
        maxFiles: '14d',
      }),
    );

    logger.add(
      new winston.transports.DailyRotateFile({
        filename: 'log/application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '1k',
        maxFiles: '14d',
      }),
    );
  }
};

export { logger, createLogger }

위는 logger를 셋팅해주고 있다.
기본적인 형식을 따르고 있는데, 주목해야 되는 부분은 크게 transports, format, level과 같다.

  • transports
    • 해당 log를 어디로 보낼지를 결정할 수 있다.
    • 여러개를 지정할 수 있다.
  • format
    • 해당 log의 format을 설정할 수 있는데, color나 out format을 json으로 할지 등등을 결정할 수 있다.
    • 직접 custom format을 작성할 수 있는데, 해당 부분은 아래에서 다루도록 한다.
  • level
    • log level을 설정할 수 있다.

2. nest logging moudle implementation

  • 크게 두 가지 방식으로 implementation이 가능한데, implements를 통해서 logging module을 delegate하거나, 또는 자체 logging을 직접 implementation 하는 방식이 있다.
  • nest.js default loggingService
  • 위의 해당 코드를 보면 알 수 있는데, 자체적으로 implementation된 logging service가 존재하는데, 완전히 커스텀하게 구현하는 것보다 필요한 부분만 구현하는 것이 좋아보여서 ( = 귀찮아서... ) 다음과 같이 구현하도록 한다.
  1. logging service를 작성한다.
// ... file 이름 이쁘게 지어주세요.
export class AppLoggingService implements LoggerService {
  log(message: string, context?: string) {
    logger.info(message, {
      from: context,
    });
  }

  error(message: string, trace: string, context?: string) {
    logger.error(message, { stack: trace, context });
  }

  warn(message: string, context?: string) {
    logger.warn(message, context);
  }

  debug(message: string, context?: string) {
    logger.debug(message, context);
  }

  verbose(message: string, context?: string) {
    logger.verbose(message, context);
  }
}
  1. boostrap에 logger를 inject한다.
// main.ts
async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    logger: new AppLoggingService(),
  });
  // ... other code
}

후기

  • nest.js에서 쉽게 logging을 적용할 수 있게 해두어서, 쉽게 적용할 수 있었다.
  • child-logger에 관련된 방식이 있는데, 해당 부분은 어떤 방식으로 수행되는지 좀 더 잘 살펴봐야겠다.
  • 간단하게 내용을 정리했지만, format쪽을 좀 더 다듬어서, 쉽게 error를 tracking하거나, transport를 file, console이 아닌 외부에 전달하는 부분도 살펴봐야한다. (이 것도 부록으로...)

출처

728x90
반응형