로깅이 중요한 이유
- 문제 파악
오류가 발생했을 때 문제점과 그 원인을 추적하고 해결하는 데 필요하다. - 성능 모니터링
애플리케이션의 성능을 분석하고 병목 현상을 식별 할 수 있다. - 보안
이상 활동을 감지하고 잠재적인 보안 위협을 파악하는 데 도움이 된다. - 기록
데이터 변경, 시스템 액세스, 사용자 활동 등의 기록을 확인 할 수 있다. - 유지 보수
사용자의 행동과 시스템 동작을 이해하여 더 나은 설계로 개선할 수 있다.
로깅에서 중요한 것
- 정확성
기록되는 로그가 실제 이벤트와 일치해야 한다. - 일관성
로그 포맷과 레벨이 프로젝트 전반적으로 일관적인 것이 좋다 - 적절한 수준
로그 레벨(debug, info, error, log)을 상황에 맞게 적절히 사용한다. - 구체성
로그 메시지가 상황에 대한 명확하고 유용한 정보를 제공해야 한다. - 보안
로그에는 민감한 데이터는 포함되지 않아야 한다.
개인적으로도 로그는 어떤 이벤트인지, 어떤 종류의 로그인지, 어떤 내용의 메시지인지가 명확하게 서비스 전반적으로 일관적이게 로그로 남아 있는 것이 좋다고 생각한다. 이전 회사에서 elk를 도입할 때에도 느낀점이 로그 정규화가 중요하다는 점이었다.
로깅 툴
단순히 console.(log, error, inf) 따위로 남길 수도 있지만, console을 사용하면 상용 단계에서 로그가 언제 호출되었는지 알기 어려우며 따로 저장하지 않으면 서버가 종료되면 로그들도 같이 사라진다. 이번에는 winston을 사용해서 로그를 남겨보려고한다.
winston은 로그 레벨 정의가 잘 되어있고, 로그를 저장할수 있는 수단도 다양하며 로그메세지 포맷 형태도 자유롭게 커스터 마이징 가능하다. 추후에 로그를 ELK와 연결하여 로그를 분석할때에도 좋다. 또한 Node.js 에서 이미 많이 쓰이고 있기 떄문에 상당히 안정적이라고 할 수 있다.
로깅 작업
- winston 패키지 설치
- npm install winston winston-daily-rotate-file
- npm install --save-dev @types/winston
- winston-daily-rotate-file 은 로그 파일을 관리해주는 모듈이다.
지정해둔 날짜 패턴(기본 1Day)에 따라 새로운 로그 파일을 생성
파일 크기 제한과 보관 기간 설정 가능
오래된 로그 파일 자동 삭제
- https://www.npmjs.com/package/nest-winston
nest-winston
A Nest module wrapper for winston. Latest version: 1.9.7, last published: 5 months ago. Start using nest-winston in your project by running `npm i nest-winston`. There are 290 other projects in the npm registry using nest-winston.
www.npmjs.com
- nest-winston의 가이드에 맞게 logger모듈 디렉토리를 생성, service, module을 작성
- NestJS에서 LoggerService를 확장해 Winston을 기반으로 커스텀 로거를 작성해서 NestJS 내부와 외부(파일, 콘솔, 데이터베이스) 를 모두 커버할 수 있는 강력한 로깅 시스템을 구축
환경 설정
common/logger/winston.config.ts
import * as winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
winston.addColors({
error: 'bold red',
warn: 'italic yellow',
info: 'cyan',
debug: 'green',
verbose: 'blue',
silly: 'magenta',
});
export const winstonConfig = {
level: 'info', // 기본 로그 레벨 설정
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.colorize(),
winston.format.printf(({ level, message, timestamp }) => {
return `[${timestamp}] ${level}: ${message}`;
}),
),
}),
new DailyRotateFile({
dirname: 'logs',
filename: '%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json(),
),
}),
],
};
common/logger/logger.service.ts , logger.module.ts
import { Injectable, LoggerService } from '@nestjs/common';
import winston from 'winston';
import { winstonConfig } from './winston.config';
@Injectable()
export class CustomLoggerService implements LoggerService {
private readonly logger: winston.Logger;
constructor() {
this.logger = winston.createLogger({
level: 'info', // 로그 레벨 설정
...winstonConfig,
});
}
log(message: string, context?: string) {
this.logger.info({ message, context });
}
error(message: string, trace?: string, context?: string) {
this.logger.error({ message, trace, context });
}
warn(message: string, context?: string) {
this.logger.warn({ message, context });
}
debug?(message: string, context?: string) {
this.logger.debug({ message, context });
}
verbose?(message: string, context?: string) {
this.logger.verbose({ message, context });
}
}
import { Module, Global } from '@nestjs/common';
import { CustomLoggerService } from './logger.service';
@Global()
@Module({
providers: [CustomLoggerService],
exports: [CustomLoggerService],
})
export class LoggerModule {}
이런식으로 설정을 하고 app.module.ts에도 LoggerModule을 등록해두면 자유롭게 쓸 수 있다.

로그 관리
현재는 파일로 logs 디렉토리에 저장 중이지만, 실제 서비스였고 규모가 꽤 커진다면 elk를 연결하여 로그를 의미있게 분석해서 사용할 수 있을 것 같다. elk역시 각각 따로 서버를 두고 이벤트 처리를 하면 될 것 이다.
'BackEnd' 카테고리의 다른 글
| 파일 송수신[1] (feat. S3, ws) (2) | 2024.12.19 |
|---|---|
| Amazon Elastic Container Service 공략 (0) | 2024.12.11 |
| 서버 모니터링 (feat. prometheus, grafana) (0) | 2024.12.08 |
| 웹소켓 연결 관리 (NestJS) (3) | 2024.11.28 |
| nestJS MongoDB 연결 및 사용하기 (0) | 2024.11.25 |