OTel 메트릭 대시보드 트러블슈팅
문제 상황#
Grafana 대시보드 “애플리케이션 모니터링(Spring Boot)“에서:
- 애플리케이션 드롭다운에 gateway만 표시됨
- auth-guard, order-core, seat, queue 등 다른 서비스가 보이지 않음
http_server_requests_seconds_count{namespace="dev-webs"}쿼리 시 gateway만 결과 반환
원인 분석#
1. 메트릭 수집 경로가 2가지로 분리되어 있었음#
| 경로 | 메트릭 이름 | 라벨 | 대상 |
|---|---|---|---|
| PodMonitor → Prometheus 직접 스크레이핑 | http_server_requests_seconds_* | status, uri, namespace | gateway만 |
| OTel Agent → OTel Collector → Remote Write | http_server_request_duration_seconds_* | http_response_status_code, http_route | 모든 서비스 |
2. gateway만 Micrometer 메트릭이 있었던 이유#
- gateway: Spring Cloud Gateway로
micrometer-registry-prometheus의존성 포함 - 다른 서비스: OTel Java Agent만 사용, Micrometer 의존성 없음
3. OTel 메트릭에 namespace 라벨 누락#
OTel Collector의 transform processor에서 namespace 라벨을 설정하려 했으나:
transform:
metric_statements:
- context: datapoint
statements:
- set(attributes["namespace"], resource.attributes["service.namespace"])
문제: OTel Java Agent가 service.namespace resource attribute를 설정하지 않고 있었음
해결#
1. Deployment에 OTEL_RESOURCE_ATTRIBUTES 추가#
java-service/templates/deployment.yaml:
{{- if .Values.otel.enabled }}
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/otel/opentelemetry-javaagent.jar"
- name: OTEL_SERVICE_NAME
value: {{ include "java-service.fullname" . }}
- name: OTEL_RESOURCE_ATTRIBUTES # 추가
value: "service.namespace={{ .Release.Namespace }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: {{ .Values.otel.collectorEndpoint | quote }}
{{- end }}
ai-service/templates/deployment.yaml에도 동일하게 추가
2. 대시보드를 OTel 메트릭으로 변경#
메트릭 이름 변경:
| Micrometer (기존) | OTel (변경) |
|---|---|
http_server_requests_seconds_count | http_server_request_duration_seconds_count |
http_server_requests_seconds_bucket | http_server_request_duration_seconds_bucket |
http_server_requests_seconds_sum | http_server_request_duration_seconds_sum |
라벨 이름 변경:
| Micrometer (기존) | OTel (변경) |
|---|---|
status | http_response_status_code |
uri | http_route |
3. 템플릿 변수 쿼리 변경#
# 기존
label_values(http_server_requests_seconds_count{namespace="$namespace"}, app)
# 변경
label_values(http_server_request_duration_seconds_count{namespace="$namespace"}, app)
4. 필터 regex 수정 (느린 엔드포인트 TOP 10)#
context-path가 포함된 경로도 필터링되도록 수정:
# 기존: /auth/actuator/health/** 같은 경로가 필터링 안 됨
http_route!~"/actuator.*|/swagger.*|..."
# 변경: 경로 중간에 있는 패턴도 매칭
http_route!~".*actuator.*|.*swagger.*|.*health.*|..."
수정된 파일 목록#
common-charts/apps/java-service/templates/deployment.yaml- OTEL_RESOURCE_ATTRIBUTES 환경변수 추가
common-charts/apps/ai-service/templates/deployment.yaml- OTEL_RESOURCE_ATTRIBUTES 환경변수 추가
common-charts/infra/monitoring/prometheus-stack/files/grafana-dashboards/dev-team-observability/application-monitoring-springboot.json- OTel 메트릭으로 변경
common-charts/infra/monitoring/prometheus-stack/files/grafana-dashboards/infra-team-observability/k6/k6-overview.json- OTel 메트릭으로 변경
- RDS/Redis 템플릿 변수 제거
- PostgreSQL 쿼리 라벨 수정 (
datname→ 제거)
메트릭 흐름도#
┌─────────────────┐
│ Java Service │
│ (OTel Agent) │
└────────┬────────┘
│ OTLP (gRPC :4317)
│ service.namespace=dev-webs
▼
┌─────────────────┐
│ OTel Collector │
│ (transform) │
│ │
│ namespace ← │
│ service.namespace
└────────┬────────┘
│ Remote Write
▼
┌─────────────────┐
│ Prometheus │
│ │
│ http_server_ │
│ request_duration│
│ _seconds_count │
│ {namespace= │
│ "dev-webs"} │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Grafana │
│ Dashboard │
└─────────────────┘
적용 순서#
java-service, ai-service 변경 배포
- dev-webs, dev-ai 앱 ArgoCD Sync
- Pod 재시작으로 OTEL_RESOURCE_ATTRIBUTES 적용
prometheus-stack 배포
- 대시보드 ConfigMap 업데이트
확인
- Prometheus에서
http_server_request_duration_seconds_count{namespace="dev-webs"}쿼리 - 모든 서비스(gateway, auth-guard, order-core, seat, queue)가 보이면 성공
- Prometheus에서
참고: OTel vs Micrometer 선택 이유#
| 항목 | OTel | Micrometer |
|---|---|---|
| 표준 | CNCF 표준, 벤더 중립 | Spring 생태계 |
| 의존성 | OTel Agent만 (runtime) | micrometer-registry-prometheus 필요 |
| 설정 | 환경변수로 설정 | application.yml |
| 메트릭 이름 | OpenTelemetry Semantic Conventions | Spring Boot 네이밍 |
결론: 모든 서비스에 OTel Agent가 이미 붙어있으므로 OTel 메트릭으로 통일