[nest.js] winston 사용법

김민재·2025년 4월 27일

nest.js

목록 보기
54/63

winston을 사용하여 db에 log를 저장하는 방법을 배워야 했다. 처음 사용해서 많이 헷갈려서 조금 힘들었지만, 내가 생각했던 흐름대로 잘 진행되었다.

🍓 Winston 사용법

🍭 모듈 다운로드

  • npm i winston nest-winston @types/winston winston-transport

🍦 logger.module.ts 생성 및 winstonModule 등록

  • 이건 전역으로 발생한다.
   WinstonModule.forRootAsync({
      useFactory: () => ({
        transports: [
          new winston.transports.Console({
            format: winston.format.combine(
              winston.format.colorize(),
              winston.format.simple(),
            ),
          }),
        ],
      }),
    }),

🌮 main.ts winston 등록

// nest 로거를 winston 기반으로 체인지 
app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER))

😾 Custom Transport DB

  • Winston Custom Transport DB 생성하기
    실질적으로 데이터를 저장할 것이다.
import * as TransportStream from 'winston-transport';
import { Injectable } from '@nestjs/common';
import { SubmissionLog } from './entities/submission-log.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

// 커스텀 DB 트랜스포트
@Injectable()
export class DBTransport extends TransportStream {
  constructor(
    @InjectRepository(SubmissionLog)
    private readonly submissionLogRepository: Repository<SubmissionLog>,
  ) {
    super();
  }

  async log(info: any, callback: () => void): Promise<void> {
    // winston에서 처리하는 로그 정보
    const { result, apiEndPoint, traceId, latency, message, submission } = info;

    try {
      // winston에서 받아서 db에 저장
      const logEntry = this.submissionLogRepository.create({
        result,
        apiEndPoint,
        traceId,
        latency,
        message,
        submission,
      });

      await this.submissionLogRepository.save(logEntry);
    } catch (error) {
      console.error('DB Logging Error:', error);
    }

    callback();
  }
}

👨‍ service 로직에서 메서드가 발생할 때 winston 실행 및 db-transport 실행

import { Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository } from 'typeorm';
import { SubmissionLog } from './entities/submission-log.entity';
import * as winston from 'winston';
import { DBTransport } from './db-transport';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { v4 as uuidv4 } from 'uuid';

@Injectable()
export class SubmissionLogService {
  constructor(
    @InjectRepository(SubmissionLog)
    private readonly submissionLogRepository: Repository<SubmissionLog>,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: winston.Logger,
  ) {
       // winston 로거 초기화
    this.logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.colorize(),
        winston.format.printf(({ timestamp, level, message }) => {
          return `[${timestamp}] ${process.pid} [${level}] ${message}`;
        }),
      ),
      transports: [
        new winston.transports.Console(),
        new DBTransport(this.submissionLogRepository),
      ],
    });
  }
  // winston 로그를 db-transport에 보내준다.
  async saveLog(info: any): Promise<any> {
    // 로그 작성

    const traceId = uuidv4();

    this.logger.info('info', {
      result: info.result, // 로그 항목에 대한 예시
      apiEndPoint: info.apiEndPoint,
      traceId: traceId,
      latency: info.latency,
      message: info.message,
      submission: info.submission,
    });

    return { success: true };
  }
}
profile
개발 경험치 쌓는 곳

0개의 댓글