콘텐츠로 이동
Study Note관측

9. 공식 앱 조사 — 세 신호를 직접 오가기

결론부터
공식 rolldice의 숫자에서 오류 문장으로, 그 문장에서 같은 요청의 트레이스로 이동한다
이 장에서 처음 나오는 말3개
조사 구간investigation window
오류와 지연이 들어 있는 시간 범위. 공식 앱은 장애 구간이 고정되지 않으므로 최근 5~15분을 직접 좁힌다.
상관 관계correlation
같은 요청의 메트릭·로그·트레이스를 시간이나 trace_id로 이어 보는 것.
exemplar표본 링크
메트릭 한 점에 매달린 대표 trace_id. 그래프에서 트레이스로 바로 건너가게 한다.

8장의 LGTM port-forward, Java example, traffic generator가 모두 실행 중이어야 한다. 공식 앱은 요청마다 임의 지연을 넣고 약 30%에서 simulating an error 예외를 던진다. 고정된 장애 시나리오가 아니라 계속 들어오는 요청 속에서 오류 요청 하나를 골라 따라가는 실습이다.

신호먼저 물을 질문이번 단서
Prometheus요청과 지연이 실제로 들어오는가request rate · p95 · 500 비율
Loki500일 때 무슨 문장이 남았나simulating an error
Tempo그 요청은 얼마나 걸렸고 어떤 상태인가GET /rolldice error span

실습 1 — 메트릭으로 오류와 지연 찾기

섹션 제목: “실습 1 — 메트릭으로 오류와 지연 찾기”

Grafana 오른쪽 위 시간 범위를 Last 5 minutes로 맞추고 Explore에서 Prometheus를 선택한다. traffic을 오래 켜 두었다면 Last 15 minutes부터 시작해도 된다.

  1. 요청이 들어오는지 확인한다

    공식 Java example의 dashboard가 사용하는 metric으로 초당 요청량을 본다.

    sum(rate(http_server_request_duration_seconds_count{
    service_name="rolldice"
    }[1m]))
  2. 상태 코드별 요청량을 나눈다

    sum by (http_response_status_code) (
    rate(http_server_request_duration_seconds_count{
    service_name="rolldice"
    }[1m])
    )

    200과 500 계열이 함께 보이면 공식 앱의 의도적 오류가 metric에도 반영된 것이다.

  3. p95 지연을 확인한다

    histogram_quantile(0.95,
    sum by (le, http_route) (
    rate(http_server_request_duration_seconds_bucket{
    service_name="rolldice"
    }[1m])
    )
    )

    공식 앱은 Gaussian 값을 바탕으로 sleep 시간을 만들므로 매 요청의 지연이 다르다. 짧은 구간의 p95가 일정하지 않은 것이 정상이다.

🔎 관찰 포인트: 약 30%는 코드의 분기 확률이지 1분 그래프가 항상 정확히 0.3이라는 뜻이 아니다. 요청 수가 적으면 비율이 크게 흔들리고, 이동창 때문에 traffic을 멈춘 뒤에도 잠시 값이 남는다.

실습 2 — 로그에서 오류 문장 찾기

섹션 제목: “실습 2 — 로그에서 오류 문장 찾기”

Explore에서 Split을 눌러 오른쪽 pane을 만들고 Loki를 선택한다. 먼저 서비스 전체 로그를 연다.

{service_name="rolldice"}

성공 로그와 framework 로그가 함께 보이면 문자열 필터를 붙인다.

{service_name="rolldice"} |= "simulating an error"

오류 한 줄을 펼쳐 trace_id · span_id · severity_text가 있는지 확인한다. 매 요청마다 바뀌는 trace_id는 Loki stream label이 아니라 구조화 metadata다. 그래서 서비스 label로 stream을 좁힌 뒤 본문과 metadata를 읽는다.

실습 3 — 오류 로그에서 Tempo로 이동하기

섹션 제목: “실습 3 — 오류 로그에서 Tempo로 이동하기”
  1. 오류 로그 상세의 trace_id 옆 Trace 링크를 누른다.

  2. Tempo에서 GET /rolldice server span의 status가 error인지 확인한다.

  3. span attribute에서 http.response.status_code=500과 http.route=/rolldice를 찾는다.

  4. Logs for this span을 눌러 같은 trace_id의 Loki 로그로 돌아온다.

Trace 링크가 없다면 Tempo Explore에서 직접 찾는다.

{ resource.service.name = "rolldice" && status = error }

공식 example은 서비스 하나라서 inventory.reserve 같은 downstream child span은 없다. 이번 실습의 성공 조건은 분산 원인 분석이 아니라 500 metric → 오류 로그 → 같은 요청의 error trace → 같은 로그가 끊기지 않는지 확인하는 것이다.

실습 4 — metric exemplar로 바로 이동하기

섹션 제목: “실습 4 — metric exemplar로 바로 이동하기”

Prometheus pane의 p95 query에서 Exemplars 표시를 켠다. 그래프 위 exemplar가 보이면 점을 눌러 trace_id와 Trace 링크를 확인한다. Grafana 공식 데이터소스 설정은 Prometheus의 trace_id를 Tempo로 보내도록 프로비저닝되어 있다.

exemplar가 없는 구간도 정상일 수 있다. 모든 측정값이 exemplar가 되는 것은 아니므로 traffic을 더 발생시키고 시간 범위를 넓혀 다시 본다. 로그 경로와 exemplar 경로 둘 중 하나만 확인하고 끝내지 않는다.

  1. [1m]을 [5m]으로 바꿔 상태 코드별 그래프와 p95가 얼마나 부드러워지는지 비교한다.
  2. {service_name="rolldice"}와 오류 문자열을 붙인 query의 결과 수 차이를 확인한다.
  3. TraceQL에서 status = error를 빼고 duration 조건을 추가해 가장 느린 성공 요청도 찾아본다.
  4. traffic을 멈춘 뒤 request rate가 즉시 0이 되지 않는 이유를 이동창으로 설명한다.
증상확인
모든 query가 비어 있음terminal A의 port-forward와 terminal B·C 프로세스가 모두 살아 있는지 확인
metric만 없음Java example 터미널의 OTLP exporter 오류와 4317·4318 전달 확인
http_response_status_code가 없음metric label browser에서 실제 status label을 확인 — agent semantic convention 차이
오류 로그가 없음{service_name="rolldice"}로 넓히고 ERROR와 exception stack trace 확인
로그에 Trace 링크 없음로그 상세에 trace_id metadata가 있는지 먼저 확인
error trace가 없음traffic을 더 발생시키고 Tempo 시간 범위를 Last 15 minutes로 확대
exemplar가 없음Prometheus query의 Exemplars 표시와 시간 범위를 확인

세 터미널과 kind 클러스터를 유지한다. 다음 장은 방금 검증한 query를 Grafana dashboard로 옮긴다. 여기서 끝낸다면 각 터미널에서 Ctrl+C를 누르고 전용 클러스터만 지운다.

터미널 창
kind delete cluster --name observability-lab