[NestJs] 추적번호 만들기

까망거북·2025년 2월 4일

nestjs

목록 보기
1/2

토이 프로젝트 진행 중 거래별로 추적번호를 만들어야 했다.

1.순서

  • middleware에서 추적번호를 생성하여 request의 header에 입력한다.
  • Interceptor에서 요청 및 응답 로그를 남긴다.
  • Controller에서 Decorator를 사용해서 추적번호를 사용한다.

2.구현

  1. 추적번호 생성
    - traceId.middle.ts

    import { Request, Response, NextFunction } from 'express';
    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { randomUUID } from 'crypto';
    
    @Injectable()
    export class TraceIdMiddleware implements NestMiddleware {
      use(req: Request, res: Response, next: NextFunction) {
        const traceId = randomUUID();
        // 추적번호를 생성하여 header에 넣는다.
        req.headers['traceId'] = traceId;
    
        next();
      }
    }
  2. 송수신 거래 로깅
    - Logging.interceptor.ts

    import { Observable } from 'rxjs';
    import { tap, catchError } from 'rxjs/operators';
    import { randomUUID } from 'crypto';
    
    import {
      Injectable,
      NestInterceptor,
      ExecutionContext,
      CallHandler,
      Logger,
    } from '@nestjs/common';
    
    @Injectable()
    export class LoggingInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const request = context.switchToHttp().getRequest();
        const method = request.method;
        const url = request.url;
        // header에서 추적번호를 찾는다.
        const traceId = request.headers['traceId'];
        const logger = new Logger(traceId);
    
        logger.log(
          `Request: ${method} ${url}, Header: ${JSON.stringify(request.headers)}`,
        );
        logger.log(
          `Request: ${method} ${url}, Body: ${JSON.stringify(request.body)}`,
        );
    
        const now = Date.now();
        return next.handle().pipe(
          tap((response) => {
            logger.log(
              `Response: ${method} ${url} ${Date.now() - now}ms ${JSON.stringify(response)}`,
            );
          }),
          catchError((error) => {
            logger.log(
              `Response: ${method} ${url} ${Date.now() - now}ms ${error.message}`,
            );
            throw error;
          }),
        );
      }
    }
  3. 데코레이터 생성
    - traceId.decorator.ts

      import { createParamDecorator, ExecutionContext } from '@nestjs/common';
    
      export const TraceId = createParamDecorator(
        (data: unknown, ctx: ExecutionContext): string => {
          const request = ctx.switchToHttp().getRequest();
          return request.headers['traceId'] || null;
        },
      );
  4. 적용

  • app.module.ts

        import { MiddlewareConsumer, Module } from '@nestjs/common';
        import { AppController } from './app.controller';
        import { AppService } from './app.service';
        import { UserModule } from './user/user.module';
        import { LoggingInterceptor } from './util/interceptor/Logging.interceptor';
        import { APP_INTERCEPTOR } from '@nestjs/core';
        import { TraceIdMiddleware } from './util/middleware/traceId.middle';
    
        @Module({
          imports: [
            UserModule,
          ],
          controllers: [AppController],
          providers: [
            // 인터셉터를 전역으로 적용한다.
            { provide: APP_INTERCEPTOR, useClass: LoggingInterceptor },
            AppService,
          ],
        })
        export class AppModule {
          configure(consumer: MiddlewareConsumer) {
            // 미들웨어를 모든 주소에 적용한다.
            consumer.apply(TraceIdMiddleware).forRoutes('*');
          }
        }
  1. 사용
    - user.controller.ts

    import {
      Controller,
      Post,
      Body,
      Logger,
    } from '@nestjs/common';
    import { UserService } from './user.service';
    import { CreateUserDto } from './dto/create-user.dto';
    import { ResponseUserDto } from './dto/response-user.dto';
    
    @Controller('user')
    export class UserController {
      constructor(private readonly userService: UserService) {}
    
      @Post('create')
      async create(
        @TraceId() traceId: string,
        @Body() createUserDto: CreateUserDto,
      ): Promise<ResponseUserDto> {
        Logger.log('traceId: ' + traceId);
        return this.userService.create(createUserDto);
      }
    }

0개의 댓글