📡 Obs · Zero→Hero
หน้าแรก/🚀 5 · Hero (Production)/รวมร่าง 3 Pillars
📖 บทเรียน⏱ ~12 นาที

รวมร่าง 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