Seize the day

POST : Backend study

Nest.js file logging을 해 보자. (winston)

file로 로그 파일을 작성해야  나중에 어떤 문제가 발생했을 때 원인파악을 할 수 있다. 때문에 file로 로그를 저장하되, 오래된 파일은 자동으로 삭제되도록하여 스토리지가 가득차는 일이 생기지 않도록 하자. 여러검색을 해 보니 winston이 가장 좋은 것 같다. 

https://velog.io/@aryang/NestJS-winston%EC%9C%BC%EB%A1%9C-%EB%A1%9C%EA%B7%B8-%EA%B4%80%EB%A6%AC  이쪽 블로그를 참조해서 조금 수정했다.

logger.utils.ts

import { utilities, WinstonModule } from 'nest-winston';
//import as winstonDaily from 'winston-daily-rotate-file';
const winstonDaily = require('winston-daily-rotate-file')
import * as winston from 'winston';
import { IS_DEVELOPMENT } from './app.const';

const PROJECT_ID = "LT";
const logDir = __dirname + '/../logs'; // log 파일을 관리할 폴더

const dailyOptions = (level: string) => {
  return {
    level,
    datePattern: 'YYYY-MM-DD',
    dirname: logDir + `/${level}`,
    filename: `%DATE%.${level}.log`,
    maxFiles: 30, //30일치 로그파일 저장
    zippedArchive: true, // 로그가 쌓이면 압축하여 관리
    format: winston.format.combine(
      winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), 
      utilities.format.nestLike(PROJECT_ID, {prettyPrint: true}),      
    ),
  };
};

const consoleOptions = {
  level: 'debug', //console은 debug 이상은 다 출력한다
  format: winston.format.combine(
    winston.format.colorize({ all: true }),
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    utilities.format.nestLike(PROJECT_ID, {prettyPrint: true}),
  ),
};

const createTransports = () => {
  const transprots : winston.transport[]= [];
  if (IS_DEVELOPMENT) {
    // Console에 출력은 개발모드일때만 한다.
    transprots.push(new winston.transports.Console(consoleOptions));
  }
  transprots.push(new winstonDaily(dailyOptions('info')));
  transprots.push(new winstonDaily(dailyOptions('warn')));
  transprots.push(new winstonDaily(dailyOptions('error')));
  return transprots;
};


export const winstonLogger = WinstonModule.createLogger({
  transports: createTransports(),
});

 파일로 저장과 console로 출력되는 내용은 같게 한다.  콘솔로 출력은 debug 이상부터 출력하지만, 파일로는 info 이상부터 쓴다. 

 

logger.middleware.ts

import {
    Inject,
    Injectable,
    Logger,
    NestMiddleware,
  } from '@nestjs/common';
  
import { Request, Response, NextFunction } from 'express';
  
  @Injectable()
  export class LoggerMiddleware implements NestMiddleware {
    constructor(@Inject(Logger) private readonly logger: Logger) {}
  
    use(req: Request, res: Response, next: NextFunction) {
      // 요청 객체로부터 ip, http method, url, user agent를 받아온 후
      const { ip, method, originalUrl } = req;
      //const userAgent = req.get('user-agent'); //express
      const userAgent = req.headers['user-agent']; // fastify

      // 응답이 끝나는 이벤트가 발생하면 로그를 찍는다.
      res.on('finish', () => {
        const { statusCode } = res;
        this.logger.log(
          `${method} ${originalUrl} ${statusCode} ${ip} ${userAgent}`,
        );
      });
  
      next();
    }
  }

이것은 Appache의 로그 파일 처럼 모든 Http 요청과 응답코드를 기록한다. 

 

전역 logger 교체 

import { winstonLogger } from './logger.utils';

...
const app = await NestFactory.create<NestFastifyApplication>(
    AppModule, 
    new FastifyAdapter(),
    {logger: winstonLogger,}
  );

 

LoggerMiddleWare 적용

import { MiddlewareConsumer, Module, Logger } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { LoggerMiddleware } from "./logger.middleware";

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService, Logger],
})
export class AppModule{
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*');
  }
}

Logger를 Inject할 수 있도록 providers에 추가한다.

 

Test

@Controller()
export class AppController {
  constructor(@Inject(Logger) private readonly logger: Logger) {}

  @Get(v1 + "hello")
  hello(@Res() res: Response) {

    this.logger.log("INFO log");
    this.logger.debug("DEBUG log");
    this.logger.warn("WARN log");
    this.logger.error("ERROR log");

    getHello(res);
  }

Console출력은..

[LT] info	2024-05-01 23:56:28 INFO log
[LT] debug	2024-05-01 23:56:28 DEBUG log
[LT] warn	2024-05-01 23:56:28 WARN log
[LT] error	2024-05-01 23:56:28 ERROR log - { stack: [ null ] }
[LT] info	2024-05-01 23:56:28 GET /lt/v1/hello 200 127.0.0.1 PostmanRuntime/7.37.3

로그 파일에는 debug는 제외하고 동일하게 저장되었다.

top

posted at

2024. 5. 1. 23:57


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크