본문 바로가기

프로그래밍/node.js

[nestjs] winston으로 로그 파일 설정하기

728x90
반응형
SMALL

nestjs 를 사용하면서 내장 로거로 로그를 남길 수 있는데 파일 저장은 지원하지 않기 때문에

winston 이라는 패키지를 사용해 로그를 파일로 기록 해야 한다

npm i nest-winston winston winston-daily-rotate-file

winston-daily-ratate-file 패키지와 함께 사용하면 로그파일을 날짜별로 관리 할 수 있다

 

그 다음 src 폴더 아래에 utils 라는 폴더를 생성하고 winston.util.ts 파일을 생성한다

import { utilities, WinstonModule } from 'nest-winston'
import * as winstonDaily from 'winston-daily-rotate-file'
import * as winston from 'winston'

const logDir = 'logs'

const createDailyLogFile = (
  level: string,
): winstonDaily.DailyRotateFileTransportOptions => {
  return {
    level,
    datePattern: 'YYYY-MM-DD',
    format: winston.format.combine(
      winston.format.timestamp({
        format: 'YYYY-MM-DD HH:mm:ss',
      }),
      winston.format.json(),
    ),
    dirname: logDir + `/${level}`,
    filename: `%DATE%.${level}.log`, // 날짜-로그레벨 명으로 파일 생성
    maxFiles: 30, // 30일치 로그 저장
    zippedArchive: true, // 로그가 쌓이면 압축해서 관리
  }
}

const color = {
  error: 'red',
  warn: 'yellow',
  info: 'green',
}

winston.addColors(color)

// error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
export const winstonLogger = WinstonModule.createLogger({
  transports: [
    new winston.transports.Console({
      level: process.env.DEV_TYPE === 'dev' ? 'silly' : 'info',
      format: winston.format.combine(
        winston.format.colorize({ all: true }),
        winston.format.timestamp(),
        utilities.format.nestLike('프로젝트명', {
          prettyPrint: true,
        }),
      ),
    }),

    new winstonDaily(createDailyLogFile('info')),
    new winstonDaily(createDailyLogFile('warn')),
    new winstonDaily(createDailyLogFile('error')),
  ],
})

createDailyLogFile 함수는 로그 레벨별로 파일을 생성하기 위해 함수로 만들었다

그리고 color 옵션을 설정하기 위해 각 로그레벨 별로 컬러를 설정하고 winston.addColors에 넣어주면 된다

그 다음 윈스턴로거 인스턴스를 생성해 주면 된다

 

new winstonDaily 각 로그레벨별 파일을 만들어 저장한다

 

이제 윈스턴로거 인스턴스를 main.ts 에 주입해줘야 하는데 nest 기본 로거를 윈스턴로거로 교체 하는 작업이다

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: winstonLogger,
  })
  const PORT = process.env.WEB_PORT
  await app.listen(PORT)
}
bootstrap()

main.ts 에 우리가 만든 윈스턴로거 인스턴스를 기본로거로 사용하겠다고 명시해 주면 된다

이 방법을 사용 하면 app.module.ts 파일에 WinstonModule.forRoot로 설정을 하면 안된다

Important: by doing this, you give up the dependency injection, meaning that forRoot and forRootAsync are not needed and shouldn't be used. Remove them from your main module.

위 처럼 공식문서에 나와 있는 내용이다

 

그런 다음 서버를 시작해 보면 아래와 같이 로그 파일들이 잘 생성이 되었을 것이다

그 다음 app.module.ts 파일에 Logger를 provider 시켜 줘야 한다

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

@Module({
  providers: [Logger],
})
export class AppModule {}

그럼 이제 윈스톤 로거를 사용할 준비가 끝났다

로거를 사용하려는 소스파일에서 아래와 같이 호출해서 사용하면 된다

import { Controller, Get, Logger } from '@nestjs/common'

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

  @Get('')
  getMain() {
    this.logger.error('error Test', 'error', AppController.name)
    this.logger.warn('warn Test', AppController.name)
    this.logger.log('info Test', AppController.name)
    return 'hello world'
  }
}

위 방법 말고 공식문서에서는 아래와 같은 방법도 지원한다

import { Controller, Inject, Logger, LoggerService } from '@nestjs/common';

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

@Inject 데코레이터를 활용해 LoggerService를 사용 할 수도 있다

이렇게 하면 모든 설정이 끝났고 윈스턴으로 로그파일을 관리 할 수 있게 되었다

 

만약 라우트 핸들러를 지나기 전에 로그를 남길 필요가 있다면 미들웨어 설정을 해주면 된다

src/middleware/logger.middleware.ts

import {
  Inject,
  Injectable,
  Logger,
  LoggerService,
  NestMiddleware,
} from '@nestjs/common'
import { Request, Response, NextFunction } from 'express'

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  constructor(@Inject(Logger) private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction) {
    const { ip, method, originalUrl } = req
    const { statusCode } = res

    this.logger.log(`${method} ${originalUrl} ${statusCode} ${ip}`)

    next()
  }
}

사용자가 요청한 정보등을 로그로 남긴 후에 라우터로 넘겨주는 미들웨어이다

 

app.module.ts

import { Logger, Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './middleware/logger.middleware'

@Module({
  providers: [Logger],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('*')
  }
}

미들웨어 파일을 생성한 후에 app.module.ts 파일에 위와 같이 설정해 주면 라우터 핸들러를 지나기 전에 미들웨어에서 로그를 먼저 처리 할 수 있다

728x90
반응형
LIST