六つのパネルがそれぞれ別の問いに答えていた
한국어 원문으로 표시합니다.
목표
결함이 든 대시보드 하나를 받아 계산값·널 처리·스택·계열 수·제목과 설명을 고치고, 같은 결함을 다음 대시보드에서도 잡는 검사기를 만들어 통과시킵니다.
왜 중요한가
대시보드가 조용히 틀리는 자리는 쿼리가 아니라 패널 옵션이다. 쿼리는 맞는데 숫자 하나짜리 패널이 평균을 보여 주고 있으면, 20분짜리 급증은 여섯 시간 평균 속에서 사라진다. 빠진 점을 이어 그리면 수집이 끊긴 사실 자체가 지워지고, 계열을 쌓으면 맨 위 선을 개별 값으로 읽게 된다. 셋 다 '틀린 값' 이 아니라 '묻지 않은 질문의 정확한 답' 이라서, 보는 사람은 자기가 틀리게 읽고 있다는 것을 알 수 없다. 그래서 패널마다 어떤 질문에 답하는지를 설명으로 못박고, 그 약속을 검사기로 지키게 만든다.
단계
lab-start-grafana로 Grafana 를 띄우고, 결함이 든 대시보드/opt/lab/gfd/gfd-misread/broken.json를 고치지 말고 그대로 Grafana 에 올리세요(uid 는 파일에 적힌gfd-misread, 패널 6개).curl로/api/dashboards/db에 POST 하면 됩니다.- 1번 패널(
요청률)은 지금 평균을 보여 줍니다. 지나간 구간을 하나 골라(1시간 이상, 끝은 지금보다 앞) 그 구간에서sum(rate(http_requests_total{job="shop-api"}[5m]))의 마지막 값·평균·최댓값을 직접 재고,/root/gfd-misread/02-calc.txt에start=end=last=mean=max=다섯 줄로 적으세요(start·end 는 epoch 초). 그리고 1번 패널의 계산값을lastNotNull로 바꿔 저장하세요. /root/gfd-misread/03-null.txt에connected=none=zero=세 줄을 적으세요. 각 줄은 그 널 처리 선택이 보는 사람에게 무엇을 주장하는지를 40자 이상으로 설명해야 하고, 세 줄은 서로 달라야 합니다. 그리고 2번 패널(대기열)의spanNulls를false로 바꿔 저장하세요.- 3번 패널(
핸들러별 요청률)은 계열을 쌓아 그립니다. 지나간 시각을 하나 골라 그 순간의 전체 합과/api/orders한 핸들러의 값을 각각 재어/root/gfd-misread/04-stack.txt에at=total=orders=세 줄로 적으세요(at 은 epoch 초). 그리고 3번 패널의stacking.mode를none으로 바꿔 저장하세요. - 4번 패널(
핸들러 지연)의 쿼리는 핸들러마다 하나씩 계열을 돌려줍니다. 그 개수를 세어/root/gfd-misread/05-series.txt의before=에 적고, 이 패널이 '지금 가장 느린 핸들러의 p95 는 얼마인가' 하나에 답하도록 쿼리를 고쳐 저장한 뒤 고친 쿼리의 계열 수를after=에 적으세요. - 여섯 패널 모두 제목을 무엇을 보는 패널인지 알 수 있게 고치고(
그래프같은 이름 금지), 설명에는 그 패널이 답하는 질문 문장을 물음표로 끝나게 적으세요(12자 이상, 패널마다 다르게). 고친 대시보드를 저장하세요. /root/gfd-misread/lint.py를 만드세요. 대시보드 JSON 파일 경로를 인자로 받아 아래 다섯 규칙의 위반을 한 줄에 하나씩(R1~R5로 시작) 출력하고, 위반이 하나라도 있으면 종료 코드 1 로 끝나야 합니다. R1 stat 패널의 계산값에 평균이 들어 있다 · R2spanNulls가 참이다 · R3stacking.mode가normal이다 · R4 설명이 물음표로 끝나지 않는다 · R5 제목이 비었거나그래프·패널·차트다. 원본/opt/lab/gfd/gfd-misread/broken.json에 돌려 다섯 규칙이 모두 잡히는지 확인하세요.- Grafana 에 올라간 지금의 대시보드를 그대로 내려받아
/root/gfd-misread/fixed.json에 저장하고(.dashboard본문만), 검사기를 돌려 위반 0 · 종료 코드 0 인 것을 확인하세요. 그리고/root/gfd-misread/08-review.md에R1=부터R5=까지 다섯 줄로 무엇을 왜 고쳤는지 각 30자 이상 적으세요.
참고
- Grafana 는
lab-start-grafana로 켭니다(몇 초 걸립니다). 웹 프리뷰 3000번 포트로 눈으로도 확인해 보세요. - 결함이 든 원본 대시보드는
/opt/lab/gfd/gfd-misread/broken.json에 있습니다. 이 파일은 고치지 말고 읽기만 하세요 — 8단계에서 다시 씁니다. - 대시보드를 저장하는 API 는
POST /api/dashboards/db이고 본문은{"dashboard": ..., "overwrite": true}입니다. - 구간 질의는
/api/v1/query_range, 한 순간의 값은/api/v1/query에time=을 함께 보냅니다. 두 경로 모두/api/datasources/proxy/uid/<uid>/뒤에 붙여 Grafana 를 거쳐 던질 수 있습니다. - 흔한 실수 ① 고친 뒤 저장하지 않는 것. 화면에서 바꿔도 API 로 저장하지 않으면 채점기가 보는 것은 옛 판입니다.
- 흔한 실수 ② 구간을
지금기준으로 잡는 것. 지나간 절대 시각으로 못박아야 다시 재도 같은 값이 나옵니다. - 패널 옵션 · 표준 옵션 · 대시보드 JSON 모델 · 대시보드 HTTP API · Prometheus 질의 API
고치기 전의 상태를 화면에 올린다
lab-start-grafana 로 Grafana 를 띄우고, 결함이 든 대시보드 /opt/lab/gfd/gfd-misread/broken.json 를 고치지 말고 그대로 Grafana 에 올리세요(uid 는 파일에 적힌 gfd-misread, 패널 6개). curl 로 /api/dashboards/db 에 POST 하면 됩니다.
저장 API 는 대시보드 본문을 dashboard 키 안에 담고 overwrite 를 함께 보냅니다. 파일에서 그 모양을 만드는 데는 jq -n --slurpfile 이 편합니다. Grafana 가 뜨는 데 몇 초 걸리니 /api/health 가 답하는지 먼저 보세요.
숫자 하나짜리 패널은 무엇을 계산한 값인가
1번 패널(요청률)은 지금 평균을 보여 줍니다. 지나간 구간을 하나 골라(1시간 이상, 끝은 지금보다 앞) 그 구간에서 sum(rate(http_requests_total{job="shop-api"}[5m])) 의 마지막 값·평균·최댓값을 직접 재고, /root/gfd-misread/02-calc.txt 에 start= end= last= mean= max= 다섯 줄로 적으세요(start·end 는 epoch 초). 그리고 1번 패널의 계산값을 lastNotNull 로 바꿔 저장하세요.
구간 질의는 /api/v1/query_range 이고 start·end·step 을 함께 보냅니다. 데이터소스 프록시로 던지면 Grafana 가 쓰는 것과 같은 경로로 갑니다. 계산값은 대시보드 JSON 의 options.reduceOptions.calcs 에 있습니다. 고정 구간으로 재는 이유는 나중에 다시 재도 같은 값이 나오게 하기 위해서입니다.
빠진 점을 잇는 것도 주장이다
/root/gfd-misread/03-null.txt 에 connected= none= zero= 세 줄을 적으세요. 각 줄은 그 널 처리 선택이 보는 사람에게 무엇을 주장하는지를 40자 이상으로 설명해야 하고, 세 줄은 서로 달라야 합니다. 그리고 2번 패널(대기열)의 spanNulls 를 false 로 바꿔 저장하세요.
수집이 끊긴 구간을 이어 그리면 그 시간에도 값이 있었던 것처럼 보입니다. 널 처리는 fieldConfig.defaults.custom.spanNulls 에 있습니다. 세 선택이 각각 어떤 상황에서 옳은지도 함께 생각해 보세요 — 옳은 답이 하나인 문제가 아닙니다.
쌓아 올린 맨 위 선은 어느 계열도 아니다
3번 패널(핸들러별 요청률)은 계열을 쌓아 그립니다. 지나간 시각을 하나 골라 그 순간의 전체 합과 /api/orders 한 핸들러의 값을 각각 재어 /root/gfd-misread/04-stack.txt 에 at= total= orders= 세 줄로 적으세요(at 은 epoch 초). 그리고 3번 패널의 stacking.mode 를 none 으로 바꿔 저장하세요.
한 순간의 값은 /api/v1/query 에 time= 을 함께 보내면 됩니다. 시각을 못박아 두어야 나중에 다시 재도 같은 값이 나옵니다. 스택 설정은 fieldConfig.defaults.custom.stacking.mode 에 있습니다. 두 숫자를 비교해 보면 맨 위 선을 개별 계열로 읽었을 때 얼마나 틀리는지 알 수 있습니다.
값 하나를 묻는 패널에 계열이 넷 오면
4번 패널(핸들러 지연)의 쿼리는 핸들러마다 하나씩 계열을 돌려줍니다. 그 개수를 세어 /root/gfd-misread/05-series.txt 의 before= 에 적고, 이 패널이 '지금 가장 느린 핸들러의 p95 는 얼마인가' 하나에 답하도록 쿼리를 고쳐 저장한 뒤 고친 쿼리의 계열 수를 after= 에 적으세요.
promq "<쿼리>" 로 던져 보면 결과 계열이 줄마다 하나씩 나옵니다. 여러 계열 중 가장 큰 값 하나만 남기는 집계 연산자가 있습니다. 쿼리는 대시보드 JSON 의 targets[0].expr 입니다.
제목과 설명이 그 패널의 질문이다
여섯 패널 모두 제목을 무엇을 보는 패널인지 알 수 있게 고치고(그래프 같은 이름 금지), 설명에는 그 패널이 답하는 질문 문장을 물음표로 끝나게 적으세요(12자 이상, 패널마다 다르게). 고친 대시보드를 저장하세요.
설명은 대시보드 JSON 의 패널마다 있는 description 입니다. 화면에서는 패널 제목 옆의 정보 표시로 나옵니다. 질문 문장으로 적어 두면 반년 뒤에 이 패널을 지워도 되는지 판단할 수 있습니다 — 그 질문을 아직 하는가만 보면 됩니다.
같은 결함을 다음 대시보드에서도 잡는다
/root/gfd-misread/lint.py 를 만드세요. 대시보드 JSON 파일 경로를 인자로 받아 아래 다섯 규칙의 위반을 한 줄에 하나씩(R1~R5 로 시작) 출력하고, 위반이 하나라도 있으면 종료 코드 1 로 끝나야 합니다. R1 stat 패널의 계산값에 평균이 들어 있다 · R2 spanNulls 가 참이다 · R3 stacking.mode 가 normal 이다 · R4 설명이 물음표로 끝나지 않는다 · R5 제목이 비었거나 그래프·패널·차트 다. 원본 /opt/lab/gfd/gfd-misread/broken.json 에 돌려 다섯 규칙이 모두 잡히는지 확인하세요.
규칙을 글로 적어 두면 다음 대시보드는 다시 같은 상태로 태어납니다. 돌아가는 코드로 적으세요. 행(row) 안에 접힌 패널도 패널이라는 점을 잊지 마세요. 파일이 {"dashboard": ...} 로 감싸여 있을 수도, 대시보드 본문일 수도 있습니다.
고친 대시보드가 스스로의 검사기를 통과한다
Grafana 에 올라간 지금의 대시보드를 그대로 내려받아 /root/gfd-misread/fixed.json 에 저장하고(.dashboard 본문만), 검사기를 돌려 위반 0 · 종료 코드 0 인 것을 확인하세요. 그리고 /root/gfd-misread/08-review.md 에 R1= 부터 R5= 까지 다섯 줄로 무엇을 왜 고쳤는지 각 30자 이상 적으세요.
파일과 화면이 갈라지지 않게 하려면 고친 뒤에 다시 내려받아야 합니다. 검사기가 0 으로 끝나지 않으면 어느 패널이 남았는지 출력이 알려 줍니다. 기록은 다음 사람이 같은 판단을 다시 하지 않게 하려고 남기는 것입니다.