LGTM stack 으로 모니터링 환경 구축 - nest.js setup
개론
이번 포스트에서는 opentelemetry sdk 를 통해 nestjs 어플리케이션이 수집하는 로그, 메트릭, 트레이스 정보를 otel collector로 내보내고, 내보낸 관측값들을 docker로 띄운 Loki, Tempo, Prometheus로 보낸 후 하나의 통합 대시보드인 grafana에서 확인하는 방법을 설명하고자 합니다.
LGTM 스택 소개 – Grafana가 밀고 있는 새로운 Observability 흐름
최근 Grafana Labs에서 적극적으로 홍보하고 있는 LGTM 스택은 다음 네 가지 오픈소스 프로젝트의 조합을 의미합니다.
- Loki: 로그 수집 및 저장소
- Grafana: 시각화 도구 및 대시보드
- Tempo: 분산 추적(트레이싱) 저장소 (APM)
- Mimir: 시계열 메트릭 저장소
왜 grafana는 LGTM 을 밀고 있을까 ?
대부분의 회사에서 시스템 모니터링, 로깅, APM 을 위해 다음과 같은 도구들을 사용합니다.
✅ 시스템 모니터링
- Prometheus + Grafana
- Zabbix
- Datadog / NewRelic (SaaS)
✅ 로그 수집 및 분석
- ELK (Elasticsearch, Logstash, Kibana)
- Loki + Grafana
- CloudWatch
- 기타 SaaS
✅ APM (Application Performance Monitoring)
- Scouter
- Elastic APM
- Pinpoint
- Datadog / Instana / etc
이러한 구성은 일반적으로 다음과 같은 문제를 가집니다.
📌 CPU / Memory 등 리소스 상태는 A에서 보고,
📌 애플리케이션 로그는 B에서 확인하고,
📌 트레이싱/성능 정보는 C에서 확인해야 합니다.
LGTM 의 목적
grafana는 이러한 복잡한 관측환경을 grafana라는 대시보드를 통해 하나로 통합하고자 합니다.
LGTM의 진짜 강점: 관측 데이터 간 연결성
단일 대시보드에서 보는 것만으로는 부족합니다.
LGTM은 로그, 트레이스, 메트릭을 서로 연결해 다음과 같은 Use Case를 가능하게 합니다:
🔍 대표적인 활용 시나리오
- Latency가 높은 특정 HTTP 요청 메트릭에서 해당 트레이스 및 로그 바로 연결 조회
- 5xx 에러가 발생한 트레이스에서 관련된 로그 자동 필터링
- 로그에서 traceId를 클릭해 해당 트레이스를 추적
- 트레이스의 특정 Span에 대한 평균 Latency 메트릭 조회
이처럼 연관된 로그/트레이스/메트릭을 유기적으로 탐색하며 디버깅할 수 있는 것이 LGTM의 핵심 장점입니다.
🎯 LGTM 통합 흐름도
[NestJS App]
│
▼
[OpenTelemetry SDK]
│
├──→ Logs ─────────────┐
├──→ Traces ─────────┐ │
└──→ Metrics ──────┐ │ │
▼ ▼ ▼
[OpenTelemetry Collector]
│
┌──────────┼────────────┐
▼ ▼ ▼
[Loki] [Tempo] [Mimir]
└──────────┬────────────┘
▼
[Grafana UI]
LGTM 구성요소
LGTM을 구성하는 요소는 각기 다른 기능을 수행하지만, 서로 유기적으로 연결되어 하나의 관측파이프라인을 형성합니다.
Loki : log에서 오류를 찾고 싶을 때
🧩 “500 에러가 났는데, 정확히 어떤 요청에서 났는지 확인하고 싶다.”
이럴 때 사용하는게 로그 저장소인 Loki 입니다. Loki는 시스템이나 어플리케이션에서 발생하는 로그를 수집하고, **필터링 가능한 쿼리(LogQL)**로 분석할 수 있게 해줍니다.
Loki는 log에 label
을 붙여 저장하고, 로그를 마치 SQL 처럼 질의하여 찾을 수 있도록 합니다.
Grafana – 모든 걸 한 화면에 연결하고 싶을 때
🧩 “어제 밤에 서비스가 느려졌는데, 메트릭/로그/트레이스 흐름을 한눈에 보고 싶다”
이럴 때 필요한 게 Grafana입니다.
Grafana는 단순한 시각화 도구가 아니라,
로그, 트레이스, 메트릭을 연결해주는 중심 허브입니다.
- 예: 특정 시간대에 CPU 사용량이 급증한 원인을 로그/트레이스로 따라가본다
- 예:
traceId
클릭 → 연관된 로그와 서비스 호출 흐름을 바로 확인
Grafana를 쓰면 여러 데이터 소스를 하나의 대시보드에서
직관적으로 탐색하고, 연결해서 보는 경험이 가능해집니다.
Tempo – 요청 흐름을 추적하고 싶을 때
🧩 “사용자가 어떤 요청을 보냈을 때, 그 요청이 어떤 서비스 → 어떤 함수 → 어디서 느려졌는지 보고 싶다”
Tempo는 분산 트레이싱(Distributed Tracing) 시스템입니다.
하나의 요청이 서비스 여러 개를 거쳐 갈 때, 그 흐름을 시각화해서 보여줍니다.
- 예: 사용자 로그인 요청이
gateway → auth → DB
를 거치는데
→auth
단계에서 지연이 발생한 걸 트레이스로 파악 - 예: 에러가 난 요청의 전체 호출 흐름을 확인
Tempo는 traceId 기반으로 로그와도 연결되기 때문에
트레이스 ↔ 로그 간 왕복 탐색도 가능합니다.
Mimir – 장기 메트릭 데이터를 저장하고 싶을 때
🧩 “CPU 사용률이 최근 3개월간 점점 높아지는 경향이 있는지 보고 싶다”
Prometheus는 메트릭 수집에는 강하지만,
오래 저장하거나 대규모 데이터를 다루는 데 한계가 있습니다.
이런 문제를 해결하기 위해 등장한 것이 Mimir입니다.
- 예: 수천 개의 서버에서 쏟아지는 메트릭을 안정적으로 저장
- 예: 6개월치 메모리 사용량 추이 그래프를 대시보드로 보여주기
Mimir는 Prometheus 쿼리와 완전히 호환되기 때문에,
기존 Prometheus 환경을 쉽게 확장할 수 있습니다.
Prometheus – 메트릭을 주기적으로 긁어오고 싶을 때
🧩 “10초마다 서버 CPU, Memory, Disk 사용량을 수집해서 모니터링하고 싶다”
Prometheus는 메트릭 수집기입니다.
애플리케이션이나 노드에 붙어서 주기적으로 데이터를 수집하고,
Grafana로 시각화할 수 있습니다.
- 예:
http_requests_total
같은 애플리케이션 메트릭 - 예:
process_cpu_seconds_total
같은 시스템 메트릭
Prometheus는 간단하고 빠르며, 대부분의 시스템 모니터링에 기본적으로 사용됩니다.
(optional) OpenTelemetry – 데이터를 수집해서 전달하고 싶을 때
🧩 “NestJS 앱에서 트레이스를 자동으로 수집하고, Collector에 보내고 싶다”
OpenTelemetry는 표준화된 수집기입니다.
각 언어의 애플리케이션에서 로그/트레이스/메트릭을 수집하고,
Collector로 전송하는 역할을 담당합니다.
- 예: NestJS에서 HTTP 요청마다 trace 정보를 자동으로 수집
- 예: 특정 로직에서 직접 trace span을 추가하거나 로그 emit
OpenTelemetry는 SDK + Collector
구조로,
앱 쪽 코드와 수집기 설정을 분리해서 운영할 수 있다는 장점도 있습니다.