NestJS로 프로젝트 수행 중 서버내에 로깅이 필요했다.👀
이를 위해 미들웨어를 이용해 로거를 만들어 적용하는 방법에 대해 설명하겠다.
미들웨어를 통해 만든다고 했으니 미들웨어가 무엇인지 알고 넘어가야 한다.
Nest 미들웨어는 기본적으로 Express 미들웨어와 동일하다.
Express 공식 문서에서 정의하는 미들웨어는 아래의 기능을 수행할 수 있다.
- 어떤 코드라도 실행 가능하다.
- 요청, 응답 객체를 변경할 수 있다.
- 요청, 응답 주기를 종료할 수 있다.
- 스택에서 다음 미들웨어 함수를 호출할 수 있다.
(사진과 같이 라우트 핸들러 이전에 호출 되는 함수)
그럼 이제 미들웨어를 알았으니 이 미들웨어를 통해 요청객체를 가로채서 로깅을 할 수 있다.
먼저 로깅 미들웨어를 작성한다 Express 미들웨어와 동일하지만 Nest는 '@nestjs/common'모듈에서 제공하는 NestMiddleware 인터페이스를 구현하는 형식으로 작성된다.import { Injectable, Logger, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggingMiddleware implements NestMiddleware { private logger = new Logger('HTTP'); //HTTP 로그를 기록하는 logger 프로퍼티를 선언 use(req: Request, res: Response, next: NextFunction) { //미들웨어 로직을 정의 const { ip, method, originalUrl } = req; //IP 주소, HTTP 메서드 및 원본 URL을 추출 const userAgent = req.get('user-agent') || ''; res.on('finish', () => { //로깅 상세설정 const { statusCode, statusMessage } = res; const logLevel = statusCode >= 400 ? 'error' : 'log'; this.logger[logLevel]( `Request from ${ip} to ${method} ${originalUrl} - ${statusCode} ${statusMessage} - ${userAgent}`, ); }); next(); } }
- 코드 설명
로깅:
응답이 완료되면 로그 레벨을 결정하고 로그를 기록한다.
상태 코드 (statusCode)가 400 이상이면 'error' 레벨로 로그를 남긴다.
그렇지 않으면 'log' 레벨로 로그를 남긴다.
로그에는 클라이언트의 IP 주소, HTTP 메서드, URL, 상태 코드, 상태 메시지 및 사용자 에이전트 정보가 포함된다.
또한 이렇게 작성된 미들웨어는 Appmodule에 등록해 주어야만 정상적으로 작동된다.
Appmodule은 Nest의 보일러플레이트 생성시 존재한다
(아래와 같이 적용)
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { LoggingMiddleware } from './logging.middleware'; @Module({ controllers: [], // 컨트롤러 등록 }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggingMiddleware).forRoutes('*'); // 모든 라우트에 미들웨어를 적용 } }
*(와일드카드)를 통해 모든 경로에 적용할수도 있지만 '/users'와 같이 특정 경로에만
적용할 수도 있다.
하지만 로거를 작성해 보면서 많은 것을 느꼈다.
미들웨어를 사용한다면 서비스로직 부분을 조금 더 깔끔하게 처리할 수 있다는 것.
데이터 검증과 같은 것들 또한 이부분에서 처리한다면 조금 더 코드를 클린하게 작성했을 것에 대한 아쉬움이 들며 많은 생각을 갖게 되었다.
DEBUG: 디버깅 목적의 정보를 기록, 개발 환경에서 주로 사용됨.
INFO: 일반적인 정보 메시지를 기록, 애플리케이션의 정상 작동 상태를 나타냄.
WARN: 경고 메시지를 기록, 어떤 문제가 발생했지만 애플리케이션은 계속 실행됨.
ERROR: 에러 메시지를 기록, 중요한 문제가 발생했고 처리해야 함.
FATAL: 치명적인 에러 메시지를 기록, 애플리케이션을 중단시켜야 하는 심각한 문제가 발생 함.
로거는 정말정말 유용하다.😁
어디서 에러가 발생하는지
누가 접속했고 뭘 했는지 모니터링도 가능하다😯
로깅 정말 중요하죠..!
프론트엔드이긴 하지만 글을 통해 로깅의 중요성을 다시 상기시키고 갑니다😁