본문으로 건너뛰기

Monitoring (Grafana LGTM)

multi-saas-kit의 공식 통합 모니터링 플랫폼입니다. 모든 프로젝트(Laravel)와 플랫폼 서비스(_services/)의 로그·메트릭·알림을 단일 Grafana 인터페이스에서 관리합니다.

개요​

항목내용
위치workspace/_devtools/monitoring
스택Grafana + Loki + Prometheus + Promtail
권장 도메인monitor.devtools.{platform-domain}
설계 문서ADR-017 (Monitoring Stack Grafana LGTM)

왜 중요한가​

운영 중인 플랫폼에서 **"지금 무슨 일이 일어나고 있는지"**를 즉시 답할 수 있어야 장애를 빨리 감지하고, 고객 문의에 근거로 답하며, 비용/사용량을 추적할 수 있습니다. 모니터링은 인프라의 필수 구성요소이지 선택 사항이 아닙니다.

multi-saas-kit은 멀티테넌트 SaaS 플랫폼이라 다음이 특히 중요합니다:

  • 여러 고객 프로젝트의 로그가 한 화면에서 조회되지만 격리되어 있어야 함
  • 에러 스파이크가 자동으로 감지되어 운영 알림 채널로 전달
  • 서비스 버전/배포 이력이 대시보드에서 추적 가능
  • AI 점검 시스템이 프로그래밍 방식으로 로그/메트릭 쿼리 가능

Grafana LGTM 스택은 이 모든 것을 OSS 기반으로 충족합니다.

스택 구성​

컴포넌트​

컴포넌트역할
Grafana대시보드, Explore UI, 알림 관리, 사용자 인증
Loki로그 저장소. Prometheus 스타일 레이블 기반
Prometheus메트릭 시계열 DB. /metrics 엔드포인트 pull
Promtail로그 수집 agent. journald + 파일 + Docker 지원
(선택) Tempo분산 트레이싱 저장소
(선택) Alertmanager고급 알림 라우팅

데이터 흐름​

[관측 대상] ──► [수집] ──► [저장] ──► [조회/알림]

Laravel storage/logs/*.log ─┐
systemd journal (Go 서비스) ─┼─► Promtail ─► Loki ──┐
Docker containers stdout ─┘ │
├─► Grafana
/metrics endpoints ──────────► Prometheus ──────────┘ │
▼
(Slack / Email /
Report files)

시작하기​

로컬 개발​

make up NAME=_devtools/monitoring

접속은 배포 환경의 monitoring 도메인을 사용합니다. 관리자 자격증명은 .env의 GRAFANA_ADMIN_PASSWORD로 관리하며 문서에 값을 기록하지 않습니다.

운영 (기존 도메인 구조 기반)​

루트 .env에 PLATFORM_DEVTOOLS_URL이 설정되어 있다면 자동으로 monitor.{platform-domain} 또는 monitor.devtools.{platform-domain}으로 접근 가능합니다.

Nginx Proxy Manager에 다음 Proxy Host 등록:

  • Domain: monitor.devtools.codebase.how
  • Forward: <monitoring-host>
  • SSL: Let's Encrypt
  • WebSocket Support: ON

설정 파일 구조​

workspace/_devtools/monitoring/
├── docker-compose.yml # 4개 서비스
├── .env.example # 환경변수 템플릿
├── Makefile
├── AGENTS.md
└── configs/
├── loki/
│ └── loki-config.yaml # 30일 retention, filesystem storage
├── promtail/
│ └── promtail.yaml # journald + Laravel + Docker scrape
├── prometheus/
│ └── prometheus.yml # scrape targets
└── grafana/
├── provisioning/
│ ├── datasources/
│ │ └── datasources.yaml # Loki + Prometheus 자동 등록
│ ├── dashboards/
│ │ └── dashboards.yaml # JSON 자동 로드
│ └── alerting/ # alerting canonical 3파일
└── dashboards/
├── overview.json
├── services-health.json
├── laravel-projects.json
└── edge-relay.json

수집 대상 설정​

Laravel 프로젝트​

특별한 설정 변경 없이 동작합니다. Laravel 기본 로그(storage/logs/laravel-*.log)를 Promtail이 tail합니다.

권장: JSON 채널 사용 — config/logging.php:

'stack' => [
'driver' => 'stack',
'channels' => ['json'],
'ignore_exceptions' => false,
],
'json' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'formatter' => Monolog\Formatter\JsonFormatter::class,
'days' => 14,
],

Loki 레이블 자동 부여:

  • project — 프로젝트 이름 (예: apis.how)
  • app — laravel
  • env — APP_ENV 값

_services/ Go 서비스​

slog JSON 출력이 systemd journal로 흐르므로 추가 작업 없음. Promtail이 _SYSTEMD_UNIT=edge-relay-service.service 같은 필터로 scrape.

Loki 레이블:

  • service — 서비스 이름 (예: edge-relay-service)
  • runtime — go
  • env — production

Docker 컨테이너 (LiteLLM 등)​

Docker daemon 소켓 접근으로 자동 수집:

# promtail.yaml
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock

메트릭 (/metrics 엔드포인트)​

각 서비스의 /metrics를 Prometheus가 주기적으로 pull:

# prometheus.yml
global:
# 저사양 호스트(P330 등)에서 Prometheus 자체 부하를 줄이기 위해 30s 권장.
# 더 짧은 간격이 필요한 잡은 잡별 scrape_interval로 개별 단축 가능.
scrape_interval: 30s
evaluation_interval: 30s

scrape_configs:
- job_name: edge-relay-service
static_configs:
- targets: ['<edge-relay-metrics-target>']
metrics_path: /metrics
scheme: https

- job_name: speech-service
static_configs:
- targets: ['<speech-metrics-target>']
metrics_path: /metrics
scheme: https
scrape_interval 선택 가이드
호스트 환경권장 scrape_interval
저사양 자가 호스팅 (4~8코어, 컨테이너 50개+)30s ~ 60s
일반 운영 서버30s (기본값)
알람 정밀도 우선 (특정 잡만)잡별 scrape_interval: 10s 오버라이드

scrape_interval을 절반으로 줄이면 Prometheus가 처리하는 시계열 수가 그만큼 늘어나 CPU/메모리 사용량이 비례 증가합니다. 대시보드 새로고침 주기보다 짧을 필요는 없습니다.

기본 제공 대시보드​

1. Overview​

  • 전체 서비스 상태 (up/down)
  • 최근 1h 총 요청 수, 에러 수, 평균 지연
  • 활성 프로젝트 수

2. Services Health​

  • _services/ 각 서비스 /healthz 결과
  • 버전, 업타임, 최근 재시작
  • 버전과 services-registry.json 일치 여부

3. Laravel Projects​

  • 프로젝트별 ERROR/WARN 로그 카운트
  • 최근 에러 메시지 테이블
  • Laravel 응답 지연 분포

4. Edge Relay​

  • 모듈별(speech, chorus) 요청 수/지연
  • 세션 검증 성공/실패율
  • 업스트림 지연

5. Logs Explorer​

  • 사용자 정의 LogQL 쿼리
  • 레이블 조합으로 빠른 필터링

LogQL 쿼리 예시​

Grafana Explore에서 바로 사용 가능:

# 1시간 내 전체 edge-relay 에러
{service="edge-relay-service",level="ERROR"} | json

# 세션 서명 검증 실패만
{service="edge-relay-service"} | json | error_code="signature_mismatch"

# apis.how Laravel 에러 중 chorus 언급
{project="apis.how",app="laravel"} |= "chorus" |= "error"

# 특정 request_id 추적 (여러 서비스 동시)
{service=~"edge-relay-service|chorus-api"} | json | request_id="abc123"

# 5분 window 에러율
sum by (service) (rate({level="ERROR"}[5m]))

알림 설정​

알림 엔진은 Grafana Alerting으로 일원화되어 있습니다 (ADR-021). 별도 watcher 데몬 없이 Grafana가 평가·디스패치·UI를 모두 담당합니다.

소스 오브 트루스​

규칙·채널·라우팅은 Grafana 네이티브 Provisioning 포맷으로 현재 Compose 경로에서 Git 관리:

구 _services/monitoring/ 폴더와 중간 변환 계층은 [ADR-021]에서 제거되었습니다. grafana_lgtm Ansible role은 아직 미구현 scaffold이며 현재 alerting 원본이 아닙니다.

동작 흐름​

alert-rules.yaml + contact-points.yaml + notification-policies.yaml
↓ _devtools/monitoring Compose read-only mount
Grafana provisioning/alerting
↓ Grafana Alerting
Discord contact point

운영 UI​

monitor.devtools.codebase.how → Alerting 메뉴에서 현재 상태, 무음, 히스토리를 확인합니다. Provisioning으로 관리되는 규칙은 UI 수정 불가(allowUiUpdates: false) — 규칙 변경은 반드시 alert-rules.yaml PR로.

심각도와 채널​

severity채널예시
criticalDiscord서비스 다운, panic
errorDiscord5xx 스파이크
warningDiscord지연 증가
infoDiscord통계성 이벤트

로그 보존 정책​

레이어보존 기간비고
Laravel storage/logs7일 (logrotate)프로젝트별
systemd journal14일 (또는 2GB)journald.conf
Docker logs7일 (100MB per container)daemon.json
Loki (중앙)30일 (기본) / 90일 (중요)loki-config.yaml
Prometheus15일--storage.tsdb.retention.time
장기 S3/R21년+Phase 3

멀티테넌시 (프로젝트 격리)​

Loki의 X-Scope-OrgID 헤더로 프로젝트별 격리 가능합니다. Grafana 데이터소스를 프로젝트별로 분리 설정하면 각 고객은 자기 프로젝트 로그만 조회.

현재: 단일 조직, 운영자만 접근. 고객 직접 접근은 Phase 3 (Laravel SSO 연동).

보안​

항목정책
Grafana 외부 접근NPM + SSL 필수
Loki/PrometheusDocker 내부 네트워크만
관리자 비밀번호GRAFANA_ADMIN_PASSWORD env 필수
로그 민감 정보API 토큰, 비번, 프롬프트 본문 로그 금지
방화벽Tailscale ACL 권장

AI 모니터링 연동​

.ai-core/config/services-registry.json에 등록된 서비스는 AI 정기 점검 대상:

  • AI는 Grafana HTTP API (/api/ds/query)로 로그/메트릭 쿼리
  • services-registry.json의 error_patterns를 LogQL로 변환
  • 결과를 .ai-core/data/reports/services/_ai-summary/{date}/에 저장
  • 이상 발견 시 AskUserQuestion으로 사용자에게 대응 제안

자세한 내용은 AI 모니터링 계약 참조.

운영 가이드​

일별 체크리스트​

  • Overview 대시보드 확인 — 이상 징후 없음
  • Slack critical 채널 미해결 항목 확인
  • .ai-core/data/reports/services/_ai-summary/{오늘} 리뷰

주별 체크리스트​

  • 저장 공간 사용률 (data/platform/monitoring/ 디스크 사용)
  • 주요 서비스 버전 업데이트 검토
  • AI 주간 보고서 검토

월별 체크리스트​

  • 보존 정책 준수 확인
  • 알림 규칙 튜닝 (false positive)
  • 미사용 대시보드 정리
  • 비용/리소스 트렌드 리뷰

트러블슈팅​

Grafana에 로그가 안 보여요​

  1. Promtail 상태 확인: docker logs -f promtail
  2. Promtail → Loki 연결 상태는 서비스 healthcheck 또는 Grafana datasource 상태에서 확인
  3. Loki 수집 확인: Grafana Explore에서 {job=~".+"} 쿼리
  4. 레이블 확인: 로그가 뜨는데 필터가 안 맞는 것일 수 있음

"Monitoring" 카드가 unreachable​

  1. _devtools/monitoring 컨테이너 기동 확인: make status NAME=_devtools/monitoring
  2. NPM Proxy Host 등록 여부
  3. SSL 인증서 발급 여부
  4. Grafana serve_from_sub_path 설정 (경로 기반 라우팅 시)

에러 알림이 너무 많아요​

  1. 알림 규칙의 threshold/for 값 상향
  2. cooldown_sec 증가
  3. severity를 error → warning으로 하향 (즉시 알림 아닌 일별 digest)

디스크 공간이 부족해요​

  1. Loki retention 단축: loki-config.yaml의 retention_period 감소
  2. Prometheus retention 단축: --storage.tsdb.retention.time=7d
  3. 장기 보관을 S3로 이관 (Phase 3)

단계별 도입 로드맵​

Phase범위상태
1기본 스택 + 로그 중앙화 + 대시보드 5개🚧 진행 중
2메트릭 확산 + contact point 운영 강화⏳ 예정
3Grafana SSO + Loki 장기 보관⏳
4AI 자가 점검 스킬 통합⏳
5Tempo (트레이싱)🔶 선택

관련 문서​