본문 바로가기
Node js/Nest js

nest 에서 metrics data 수집하기 (서버 모니터링 용)

by Bill Lab 2025. 2. 4.
728x90

이를 위해 npm 부터 설치하자

yarn add prom-client

 

아래와 같이 서비스 레이어 부터 작성해 준다.

(prom-client 에서 얻은 정보를 컨트롤러로 공유하기 위한 목적이다.)

import { Injectable } from '@nestjs/common';
import * as promClient from 'prom-client';

@Injectable()
export class BaseService {
  private readonly collectDefaultMetrics: () => void;
  private readonly httpRequestsTotal: promClient.Counter<string>;
  private readonly httpRequestDurationSeconds: promClient.Histogram<string>;

  constructor() {
    //기본 메트릭 세팅
    this.collectDefaultMetrics = promClient.collectDefaultMetrics;
  
    this.httpRequestDurationSeconds = new promClient.Histogram({
      name: 'http_request_duration_seconds',
      help: 'Histogram of HTTP request duration in seconds',
      labelNames: ['method', 'status_code'],
      buckets: [0.1, 0.2, 0.5, 1, 2, 5, 10], // 요청 시간을 구간별로 측정
    });
  }

  //HTTP 요청을 수집
  public recordHttpRequestDuration(
    method: string,
    statusCode: string,
    duration: number,
  ) {
    this.httpRequestDurationSeconds.observe(
      { method, status_code: statusCode },
      duration,
    );
  }

  //default 메트릭 수집기의 수집경로를 맞춤
  public async getMetrics(): Promise<string> {
    return promClient.register.metrics(); // 메트릭을 문자열로 반환
  }
}

 

 

서비스 파일이 작성되었으면, 컨트롤러도 작성해준다.

(일반적으로 metrics data 수집의 default 경로는 /metrics 가 되기때문에 컨트롤러로 해당 경로로 맞춰준다.

import { Controller, Get } from '@nestjs/common';
import { BaseService } from './base.service';

//default 경로를 위해 지정
@Controller('metrics')
export class BaseController {
  constructor(private readonly baseService: BaseService) {}

  @Get()
  async getMetrics() {
    return this.baseService.getMetrics();
  }
}

 

자 이제 미들웨어를 이용해보자

미들웨어는 각 어플리케이션 동작마다 소요시간과 응답을 기록하기 위함이다.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { BaseService } from './base.service';

@Injectable()
export class BaseMiddleware implements NestMiddleware {
  constructor(private readonly baseService: BaseService) {}

  use(req: any, res: any, next: () => void) {
    const start = Date.now(); 
   
    res.on('finish', () => {
      const duration = (Date.now() - start) / 1000; 
      
      this.baseService.recordHttpRequestDuration(
        req.method,
        res.statusCode.toString(),
        duration,
      );
    });

    next();
  }
}

 

위를 메트릭 모듈 생성 후 app.module 에 등록 하면 끝!

app.module 도 살짝 수정이 필요한데,,,(미들웨어를 추가해보자)

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(BaseMiddleware).forRoutes('*');
  }
}
728x90