รวมร่าง 3 Pillars
คุณมีครบ 3 เสาแล้ว แต่พลังจริงไม่ได้อยู่ที่การมีทั้งสาม — มันอยู่ที่การ เชื่อมทั้งสามให้กระโดดไปมาได้ ตอน debug ถ้าต้องเปิด 3 หน้าจอแยกกันแล้วเดาว่าอันไหนคู่กัน คุณยังไม่ได้ observability ที่แท้จริง
เป้าหมาย: กระโดดข้าม pillar ได้ใน 1 คลิก
flow ในฝัน (ต่อยอดจากบทที่ 01):
📈 Metric alert: "error rate พุ่ง"
│ คลิก exemplar บนกราฟ
▼
🔬 Trace: เห็น span ที่ error / ช้า
│ คลิก trace_id
▼
🪵 Logs: อ่าน log ของ request นั้นเป๊ะๆ ว่าพูดว่าอะไร
▼
✅ เจอ root cause
ทั้งหมดนี้ไหลลื่นได้เพราะมี ตัวเชื่อม ร่วมกัน 2 อย่าง: trace_id และ exemplars
ตัวเชื่อมที่ 1: trace_id ใน log (Trace ↔ Log)
นี่คือตัวเชื่อมที่ทำง่ายสุดและคุ้มสุด — ใส่ trace_id (และ span_id) ลงในทุก log line
จำจากบทที่ 30: structured log ที่มี trace_id ทำให้:
{ "level": "error", "service": "payment", "trace_id": "a1b2c3", "msg": "charge failed: pool exhausted" }
เมื่อดู trace ใน Jaeger เห็น trace_id: a1b2c3 → เอาไปค้นใน Kibana trace_id: "a1b2c3" → เห็น log ทุกบรรทัดของ request นั้นจากทุก service เรียงกัน
OpenTelemetry (บทที่ 41) ฉีด
trace_id/span_idเข้า log context ให้อัตโนมัติได้ (log correlation) — instrument ด้วย OTel แล้ว log กับ trace ก็ผูกกันเองโดยแทบไม่ต้องทำอะไรเพิ่ม นี่คือเหตุผลใหญ่ที่ OTel คุ้มค่า
ตัวเชื่อมที่ 2: Exemplars (Metric ↔ Trace)
Exemplar = จุดตัวอย่างบนกราฟ metric ที่แนบ trace_id ไว้ พูดง่ายๆ คือ "ค่า latency จุดนี้ที่พุ่งสูง มาจาก trace อันนี้นะ"
p99 latency
│ ● ← exemplar (คลิกได้ → เด้งไป trace ที่ทำให้จุดนี้พุ่ง)
│ ╱
│ ─────╯
└──────────────────▶ time
แทนที่จะเห็นแค่ "p99 พุ่งตอน 10:30" แล้วต้องไปเดาหา trace เอง — คลิก exemplar แล้วเด้งไป trace ตัวอย่างที่ทำให้ค่าพุ่งได้เลย (Grafana + Prometheus + Tempo รองรับ flow นี้)
Exemplars ต่อ metric (aggregate, บอกว่ามีปัญหา) เข้ากับ trace (รายตัว, บอกว่าทำไม) โดยตรง — เป็นสะพานข้ามช่องว่างที่ใหญ่ที่สุดในการ debug: จาก "ภาพรวมแย่" ไปสู่ "ตัวอย่างจริงที่แย่"
Correlation ต้องมี "แกนร่วม" (consistent labels)
ให้ทั้ง 3 เสา filter ด้วยชื่อเดียวกันได้ ต้องตั้ง label/field ให้ สอดคล้องกันข้าม pillar:
| มิติ | ใน metrics | ใน logs | ใน traces |
|---|---|---|---|
| service | service="payment" |
"service": "payment" |
service.name=payment |
| environment | env="prod" |
"env": "prod" |
deployment.environment=prod |
| version | version="1.4.2" |
"version": "1.4.2" |
service.version=1.4.2 |
ถ้า service ชื่อ
paymentใน metrics แต่payment-apiใน logs แต่PaymentServiceใน traces — คุณจะ correlate ไม่ได้เลย ต้องบังคับ naming convention เดียวกันทั้งองค์กร (OTel Semantic Conventions ช่วยเรื่องนี้ เพราะกำหนดชื่อ attribute มาตรฐานให้)
สถาปัตยกรรมที่รวมทุกอย่าง: OTel Collector เป็นศูนย์กลาง
รวมทุกบทที่เรียนมาเป็นภาพเดียว — สถาปัตยกรรม observability สมัยใหม่:
┌─── metrics ──▶ Prometheus ─┐
แอป (instrument │ │
ด้วย OTel ครั้งเดียว) ─▶ OTel Collector ─┼─── traces ───▶ Jaeger/Tempo ─┼─▶ Grafana
│ │ (หน้าจอเดียว
└─── logs ─────▶ Loki/ELK ─────┘ correlate กันได้)
- instrument ครั้งเดียว ด้วย OTel → ได้ทั้ง 3 เสา
- Collector fan-out ไปแต่ละ backend
- Grafana เป็นหน้าจอเดียว ที่ดูได้ทั้ง metric, log (Loki), trace (Tempo) และกระโดดข้ามกันด้วย trace_id/exemplar
stack นี้มีชื่อเล่นว่า "LGTM" (Loki, Grafana, Tempo, Mimir) ของ Grafana Labs — เป็นทางเลือกที่รวม 3 pillars ในบ้านเดียว คุณไม่จำเป็นต้องใช้ยี่ห้อนี้ แต่ concept การรวมศูนย์แบบนี้คือทิศทางของวงการ
สรุป
- พลังของ observability = การกระโดดข้าม pillar ได้ ไม่ใช่แค่มีครบ 3 เสา
trace_idในทุก log เชื่อม trace ↔ log (ทำง่ายสุด คุ้มสุด, OTel ฉีดให้อัตโนมัติ)- Exemplars เชื่อม metric ↔ trace (คลิกจุดบนกราฟ → เด้งไป trace)
- ต้องมี naming convention เดียวกันข้าม pillar ไม่งั้น correlate ไม่ได้
- สถาปัตยกรรมสมัยใหม่: instrument ด้วย OTel ครั้งเดียว → Collector → fan-out → ดูรวมใน Grafana
บทสุดท้าย: เอา monitoring ทั้งหมดไปใช้ตอนไฟไหม้จริง — On-call, Incident & Postmortem