02. Lens 시각화 8종 레시피¶
목표: 운영 현장에서 자주 쓰는 시각화 패턴 8종을 직접 만들 수 있다. 선수: 01-quickwin.md — 한 번이라도 Lens 로 차트 만들어 저장한 경험 소요: 각 레시피 5~10분 × 8 = 60분 (다 안 해도 됨, 필요한 것만)
Lens 의 핵심 개념 30초¶
flowchart LR
DV[Data View] --> L[Lens]
L -->|configure| AXIS["📐 axis<br/>(X / Y / Breakdown)"]
AXIS -->|drag| FIELD[필드]
FIELD --> AGG["⚙️ Aggregation<br/>Count / Sum / Avg ..."]
AGG --> BUCKET["🪣 Bucket<br/>Date histogram /<br/>Terms / Filters"]
BUCKET --> CHART[차트 출력]
style L fill:#bbdefb,stroke:#1976d2
Lens 는 GUI drag&drop 으로 차트 설정 → 내부적으로 ES aggregation query 를 빌드해 보여주는 도구.
📌 Oracle 비유:
- axis = SELECT 의 컬럼 위치 (X/Y/색상 분리)
- aggregation = COUNT/SUM/AVG/MIN/MAX
- bucket = GROUP BY (시간 구간 / terms / range / filter)
레시피 인덱스¶
| # | 차트 | 차트 타입 | 핵심 학습 |
|---|---|---|---|
| B1 | 시간별 API 호출량 (서비스별) | Stacked area | Date histogram, breakdown |
| B2 | Top 10 API 호출량 | Horizontal bar | Terms aggregation |
| B3 | 메소드 분포 | Donut | Pie/donut + 작은 카디널리티 |
| B4 | 요일×시간 heatmap | Heatmap | 2-dimension grouping |
| B5 | API별 p50/p95/p99 latency | Bar + multi-metric | Percentile aggregation |
| B6 | 에러율 % trend | Line + Formula | Formula (분자/분모) |
| B7 | Top 에러 코드 | Horizontal bar | KQL filter + terms |
| B8 | 서비스별 에러 분포 | Stacked bar | Filter+breakdown 조합 |
공통 출발점¶
각 레시피 시작 전 한 번씩:
1. Analytics → Visualize Library → Create new visualization → Lens
2. Data view: api-logs
3. 시간 피커: Last 7 days (Last 30 days 도 OK)
B1. 시간별 API 호출량 (서비스별)¶
Why¶
가장 자주 보는 1번 차트. 트래픽 패턴 + 서비스별 비중 을 한 화면에. peak/trough 가 시각적으로 즉시 보임.
차트 타입¶
Area stacked
설정¶
Horizontal axis ← @timestamp (Date histogram, Auto interval)
Vertical axis ← Records (Count of records)
Breakdown ← service_name (Top 10)
Oracle SQL 등가¶
sql
SELECT
TRUNC(ts, 'HH24') AS hour_bucket,
service_name,
COUNT(*) AS calls
FROM api_logs
WHERE ts >= SYSDATE - 7
GROUP BY TRUNC(ts,'HH24'), service_name
ORDER BY hour_bucket
✅ Verify¶
- 8 색상 stack
- 7일 분량 막대 (시간 단위로 더 잘게)
- 마우스 hover 시 시각별 서비스별 정확한 카운트
Variations / Tips¶
| 원하는 변형 | 방법 |
|---|---|
| Stacked → 100% 정규화 (비중 비교) | Vertical axis 의 ⋯ → "Normalize by unit" 또는 Lens의 "Percentage" 옵션 |
| 서비스 너무 많아서 어수선 | Breakdown 의 "Number of values" 5로 줄이기 + "Other" 활성 |
| 시간 그루핑 굵게/얇게 | Horizontal axis interval 을 1h/30m/1d 명시 |
B2. Top 10 API 호출량¶
Why¶
"가장 많이 쓰는 API 가 뭐지?" 를 즉시 답. 사용 빈도 ↔ 중요도 추정.
차트 타입¶
Bar horizontal
설정¶
Vertical axis ← api_path (Terms, Top 10, Order by Count desc)
Horizontal axis ← Records (Count of records)
Oracle SQL 등가¶
sql
SELECT api_path, COUNT(*) AS calls
FROM api_logs
GROUP BY api_path
ORDER BY calls DESC
FETCH FIRST 10 ROWS ONLY
✅ Verify¶
- 막대가 10개
- 가장 위가 가장 많이 호출된 path
Tips¶
- legacy 의
header.uri를 쓰는 인덱스에선 data view 를legacy-api-logs로 바꾸고 필드 이름만 다름 - terms aggregation 은 정확값이 아닌 근사값 (shard 별 top → coordinator 합산) — 정확하려면 size 키우기
B3. 메소드 분포¶
Why¶
GET / POST / PUT / DELETE 비율. 읽기 vs 쓰기 트래픽 비중 추정.
차트 타입¶
Donut (Pie 도 OK)
설정¶
Slice by ← http_method (Terms, Top 5)
Size by ← Records (Count)
Oracle SQL 등가¶
sql
SELECT http_method, COUNT(*) FROM api_logs GROUP BY http_method
✅ Verify¶
- 색상 4종 (GET, POST, PUT, DELETE)
- POST 가 가장 큼
📌 언제 안 쓰나: 카디널리티 (서로 다른 값의 개수) 가 10개 넘으면 donut 은 가독성 떨어짐 → bar chart 가 낫다.
B4. 요일 × 시간 heatmap¶
Why¶
peak 시간대 패턴. "월요일 9시가 가장 바쁘다" 같은 비즈니스 통찰.
차트 타입¶
Heatmap
설정¶
Horizontal axis ← @timestamp (Date histogram, interval = 1 hour, formatter "HH")
Vertical axis ← @timestamp (Date histogram, interval = 1 day, formatter "EEE" or "yyyy-MM-dd")
Cell value ← Records (Count)
⚠️ Lens 가 같은 필드(
@timestamp) 두 번 사용은 가능하지만 다른 interval 로 명시 필요.
더 쉬운 대안 (시각화 라이브러리 제약 시)¶
요일 + 시간을 직접 추출하기 어렵다면: - 우선 시간 축만 쓰는 hourly histogram 을 만든 뒤 - 시간 피커로 1주를 7번 보면서 패턴 비교 - 또는 Vega/Vega-Lite 시각화로 직접 (고급)
Oracle SQL 등가¶
sql
SELECT
TO_CHAR(ts, 'D') AS dow, -- 요일
TO_CHAR(ts, 'HH24') AS hr,
COUNT(*)
FROM api_logs
GROUP BY TO_CHAR(ts,'D'), TO_CHAR(ts,'HH24')
✅ Verify¶
- 24열 × 7행 grid
- 색상 농도 차이로 peak 가시화
B5. API별 p50 / p95 / p99 latency¶
Why¶
평균 latency 만 보면 outlier 가 가려짐. p95/p99 가 진짜 사용자 경험. SLI/SLO 의 핵심 지표.
차트 타입¶
Bar vertical (또는 horizontal)
설정¶
``` Horizontal axis ← api_path (Terms, Top 10) Vertical axis ← 3개 metric 추가: 1. Percentile of elapsed_ms, percentile = 50 2. Percentile of elapsed_ms, percentile = 95 3. Percentile of elapsed_ms, percentile = 99
(KQL filter) ← log_type : "out" ← 이 필터 꼭! ```
KQL 필터 추가법¶
좌상단 검색창에 입력 또는 차트 위 filter:
log_type : "out"
(elapsed_ms 는 응답 시점에만 기록되므로 in 로그까지 합치면 0 이 섞임 → percentile 왜곡)
Oracle SQL 등가¶
sql
SELECT
api_path,
PERCENTILE_DISC(0.50) WITHIN GROUP (ORDER BY elapsed_ms) AS p50,
PERCENTILE_DISC(0.95) WITHIN GROUP (ORDER BY elapsed_ms) AS p95,
PERCENTILE_DISC(0.99) WITHIN GROUP (ORDER BY elapsed_ms) AS p99
FROM api_logs
WHERE log_type = 'out'
GROUP BY api_path
ORDER BY COUNT(*) DESC
FETCH FIRST 10 ROWS ONLY
✅ Verify¶
- API 마다 막대 3개 (p50, p95, p99)
- p50 < p95 < p99 (당연)
- 단위 ms
📌 Tip: 하나의 정수가 아니라 분포가 궁금하면 B5 변형: histogram (Distribution chart, X=elapsed_ms, Y=count).
B6. 에러율 % trend¶
Why¶
KPI. 트래픽 절대량과 무관하게 품질을 측정.
차트 타입¶
Line
설정¶
Horizontal axis ← @timestamp (Date histogram)
Vertical axis ← Formula:
count(kql='log_type : "out" and not data.resultCode : "0000"')
/ count(kql='log_type : "out"')
Vertical axis 의 Format = Percent (또는 Number * 100, suffix %)
Oracle SQL 등가¶
sql
SELECT
TRUNC(ts,'HH24') AS hr,
COUNT(CASE WHEN log_type='out' AND data.resultCode <> '0000' THEN 1 END) * 100.0
/ NULLIF(COUNT(CASE WHEN log_type='out' THEN 1 END), 0) AS error_pct
FROM api_logs
GROUP BY TRUNC(ts,'HH24')
✅ Verify¶
- Y축 % 단위
- 평균 ~17% (우리 mock 데이터)
📌 응용: 분모를 count() (모든 레코드) 로 바꾸면 "전체 트래픽 대비 에러" 가 됨. 보통 분모를 out 으로 한정해야 의미 있음 (in 은 요청이라 에러 개념 없음).
B7. Top 에러 코드¶
Why¶
어떤 에러가 가장 많은가? 를 즉시 답. 우선 대응 순위.
차트 타입¶
Bar horizontal
설정¶
KQL filter ← log_type : "out" and not data.resultCode : "0000"
Vertical axis ← data.resultCode (Terms, Top 10)
Horizontal axis ← Records (Count)
Oracle SQL 등가¶
sql
SELECT data.resultCode, COUNT(*)
FROM api_logs
WHERE log_type='out' AND data.resultCode <> '0000'
GROUP BY data.resultCode
ORDER BY COUNT(*) DESC
FETCH FIRST 10 ROWS ONLY
✅ Verify¶
- 막대 10개 (또는 데이터 적으면 그 이하)
- 9999, E001~E902, P001~P401 등이 빈도순
Variations¶
- 차트 옆에 resultMsg 도 같이 보여 주려면: 또 하나의 visualization (table) 만들어
data.resultCode + first(data.resultMsg)컬럼
B8. 서비스별 에러 분포¶
Why¶
어느 서비스가 에러가 많이 나는가? Top 에러 코드(B7) 와 서비스 차원으로 분리해 보면 우선순위 명확.
차트 타입¶
Bar vertical (stacked) 또는 horizontal
설정¶
KQL filter ← log_type : "out" and not data.resultCode : "0000"
Horizontal axis ← service_name (Terms, all 8)
Vertical axis ← Records (Count)
Breakdown ← data.resultCode (Top 5) ← 서비스 안의 에러 코드 분포
Oracle SQL 등가¶
sql
SELECT service_name, data.resultCode, COUNT(*)
FROM api_logs
WHERE log_type='out' AND data.resultCode <> '0000'
GROUP BY service_name, data.resultCode
ORDER BY service_name
✅ Verify¶
- X 축 8 서비스
- 각 막대가 5색 stack (서비스별 주된 에러 코드 5종)
응용¶
- "에러율 %" 을 보고 싶으면 vertical axis 를 Formula 로 (B6 처럼)
⚙️ 모든 레시피 공통 — 핵심 설정 5개¶
1. Date histogram interval → 적절한 단위 (Auto / 1h / 1d)
2. Terms 의 size (Top N) → 10이 default, 너무 많으면 잘리고 너무 적으면 정보 누락
3. Order by → count desc / metric / alphabetical
4. Other 처리 → 활성화 시 잘린 항목 합산
5. Missing values → null/missing field 처리
❓ Self-check¶
-
Q. Lens 의
Records필드는 무엇?
A
"전체 행 수" 를 의미하는 가상 필드 = Oracle 의 `COUNT(*)`. 어떤 실제 필드도 가리키지 않음. -
Q. B5 (latency) 에서
log_type : "out"필터를 빼면 왜 안 됨?
A
in 로그에는 `elapsed_ms` 가 없음 (응답 시점에만 기록). 0 또는 missing 으로 처리되어 percentile 이 왜곡됨. -
Q. B6 (error rate) 의 분모를
count()(모든 docs) 로 바꾸면?
A
에러율이 약 절반으로 보임 (in 도 분모에 들어감). 보통 분모를 out 으로 한정해야 의미 있음. -
Q. Terms aggregation 의 결과가 정확하지 않을 수 있다는 이유?
A
샤드별 local top → coordinator 합산 방식이라 카디널리티 큰 필드는 근사값. 정확한 top N 이 필요하면 size 를 의심스러운 값보다 충분히 크게 설정.
다음: 03-dashboards.md — 위 8개 차트를 3개의 의미 있는 dashboard 로 조립.