미들웨어를 이용하여, 요청이 들어오는 모든 api에 대해 log를 남길 수 있도록 해보자.
Before begin
사실, 서버로 들어오는 모든 요청에 대해 로그를 만들어 DB에 저장하기 위해 이 작업은 시작되었다.
아래 그림은 NestJS에서 제공하는 Middleware flow와 NestJS의 LifeCycle이다.
Middleware???
위 그림에서 볼 수 있듯이 Middleware는 route handler 함수에 들어가기 전에 실행되는 함수이다.
그리고 이 Middleware Function에서는 request 객체, response 객체, next 함수에 접근이 가능하다.
기본 아이디어
처음에는 인터셉터에서 Log를 남겨보려고 하였으나, 이렇게 되면 가드에 막히는 요청들은 로그를 남길 수 없게 되어 기각했다.
그렇다면 middleware에서 일단 들어오는 모든 api요청에 대해 모든 Log를 남기고,
만약 중간 과정에서 Error가 발생한다면, ExceptionFilter부분에서 잡아서 한번 더 남기는 방식으로 처리하면 어떨까 라는 생각이 들었다.
우선 여기에서는 Middleware에서 로그를 DB에 저장하는 것만 다룰 예정이다.
구현 방법
실제로 위의 아이디어를 구현하기 위해서 건드려야 하는 부분은 2부분(미들웨어 구현파일, 미들웨어 적용)이다.
미들웨어 구현
내가 구현해본 loggerMiddleware.ts의 모습은 아래와 같다.
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { Logger } from '@nestjs/common';
import { AuditLogImple } from 'src/system-log/log.service';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
//콘솔에 출력할 수 있는 logger를 멤버변수로 등록
private logger = new Logger('HTTP');
constructor(
private auditLogImple: AuditLogImple,
//...
) {}
//use함수에서 req, res, next에 모두 접근 가능하다
use(req: Request, res: Response, next: NextFunction) {
const { ip, method, originalUrl } = req;
//...
//기존에 만들어 두었던 DB에 저장하는 메소드를 통해 원하는 방식으로 log저장
this.auditLogImple.saveAuditLog({
access_id: id,
access_ip: ip.split(':')[3],
log_levels: 'Info',
content: originalUrl,
detail_info: 'the bestLog ever',
});
//관리콘솔에 log를 출력
const userAgent = req.get('user-agent') || '';
res.on('finish', () => {
const { statusCode } = res;
this.logger.log(
`${method} ${statusCode} - ${originalUrl} - ${ip} - ${userAgent}`,
);
});
//next함수를 호출함으로써 router handler로 해당 요청을 넘겨줄 수 있다.
next();
}
}
미들웨어 적용
자, 이제 구현해 놓은 미들웨어를 적용하는 부분만 남았다.
app.module.ts에 우리가 만든 미들웨어를 적용시켜주자.
//...
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
위의 코드는 모든 api 요청에 대해 로그를 남기게 된다.
만약, 특정 라우터에만 미들웨어를 적용 시키고 싶다면, 아래 코드처럼 적용하고자 하는 Controller를 forRoutes에 인자로 전달하자.
'NestJS' 카테고리의 다른 글
DB 테이블을 entity로 만들기(nestjs) (0) | 2022.05.25 |
---|---|
main.ts 에서 nestjs module 사용하기 (feat. nestjs 서버 시작 로그 남기기) (0) | 2022.05.12 |
nestJS app 밖에서 nestJS application instance 사용하기 (0) | 2022.04.29 |
migration 으로 DB 초기값 설정(with typeorm) (0) | 2022.04.28 |
[NestJS] filter안에 dependency injection하기(i.e. inject service) (0) | 2022.04.15 |