만든 애플리케이션이 실행되는 동안 발생하는 이벤트를 기록하기 위해 로거를 사용해보겠다. 이렇게 기록된 로그를 통해 문제를 진단하고, 시스템의 성능을 모니터링 할 수 있기 때문에 반드시 로그를 남기는 것이 좋다.
NestJS는 내장된 logger 클래스가 있으며, 이를 사용하면 콘솔에 로그를 출력할 수 있다. 내장 logger에는 다음과 같은 메서드가 있다.
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class MyService {
private logger = new Logger(MyService.name);
doSomething() {
try {
// ... 여기에 비즈니스 로직 ...
this.logger.log('Doing something...');
} catch (error) {
this.logger.error('An error occurred!', error.stack);
}
}
}
이렇게 간단하게 어떤 부분에 해당하는 로거인지를 지정하여 로거를 생성한 후 각 메서드를 통해 로그 메세지를 출력할 수 있다.
하지만 이렇게 콘솔에만 로그를 출력하는 것은 개발 중이거나 디버깅할 때는 용이할 수 있지만 운영환경에서는 시스템이 재부팅되거나 콘솔 세션이 닫힌 경우 로그가 사라지고, 검색과 분석도 어려우며, 로그 모니터링을 하는데 제한이 있는 등의 문제점이 있을 수 있기 때문에 파일이나 데이터베이스 등에 저장하는 것이 좋다.
winston
이라는 로깅 라이브러리를 사용하면 파일로 로그를 기록할 수 있다.
npm install winston
npm install @types/winston --save-dev
import { Injectable, LoggerService } from '@nestjs/common';
import * as winston from 'winston';
@Injectable()
export class WinstonLoggerService implements LoggerService {
private readonly logger: winston.Logger;
constructor() {
this.logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// 콘솔 출력 설정 (개발 중에 유용함)
if (process.env.NODE_ENV !== 'production') {
this.logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
}
log(message: string) {
this.logger.log({ level: 'info', message });
}
error(message: string, trace: string) {
this.logger.log({ level: 'error', message, trace });
}
warn(message: string) {
this.logger.log({ level: 'warn', message });
}
// 기타 필요한 메서드(debug, verbose 등) 구현...
}
import { Module } from '@nestjs/common';
import { WinstonLoggerService } from './winston-logger.service';
@Module({
// ...
providers: [WinstonLoggerService],
})
export class AppModule {}
app.module.ts에 providers 리스트에 이전에 생성한 커스텀 로거를 추가하여 NestJS 모듈에 로거로 제공하도록 설정을 한다.
import { Injectable, Logger } from '@nestjs/common';
import { WinstonLoggerService } from './winston-logger.service';
@Injectable()
export class MyService {
constructor(private logger: WinstonLoggerService) {} // 이 부분 수정
doSomething() {
try {
// ... 여기에 비즈니스 로직 ...
this.logger.log('Doing something...');
} catch (error) {
this.logger.error('An error occurred!', error.stack);
}
}
}
이전에 내장 logger를 사용하던 부분에서 logger를 생성하던 부분을 커스텀 로거를 주입하는 형태로 바꿔서 사용한다.