📡 Obs · Zero→Hero
หน้าแรก/🔬 4 · Traces/Lab: OpenTelemetry + Jaeger
🧪 LAB⏱ ~40 นาที

Lab: OpenTelemetry + Jaeger

Lab สุดท้ายและมันที่สุด! คุณจะ instrument สอง service ด้วย OpenTelemetry แล้วดู trace แบบ waterfall ที่ request วิ่งข้าม service — เห็นกับตาว่า tracing ตอบคำถาม "ช้าตรงไหน" ได้ยังไง

ไฟล์พร้อมรันที่ docker/tracing/lab-traces-01/ — มี gateway, order-service (แต่ละตัว auto-instrument ด้วย OTel) และ Jaeger all-in-one

Stack: gateway → order-service → (จำลอง DB) ทุก span ส่งเข้า Jaeger

ขั้นที่ 0: เข้าใจ flow

ผู้ใช้ → GET /checkout → [gateway] ──http──▶ [order-service] ──▶ (2 fake DB queries)
                            │                     │
                            └── ส่ง trace (OTLP) ──┴──▶ [Jaeger]  ◀── ดูที่ :16686

gateway เรียก order-service ผ่าน HTTP — OTel จะส่ง traceparent header ให้อัตโนมัติ (context propagation จากบทที่ 40) ทำให้ span ของทั้งสอง service อยู่ใน trace เดียวกัน

ขั้นที่ 1: ดูจุดสำคัญในโค้ด

gateway/tracing.js — auto-instrumentation ทั้งหมดอยู่ที่นี่ (บทที่ 41):

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter(),        // ส่ง OTLP ไป Jaeger
  instrumentations: [getNodeAutoInstrumentations()], // auto: express + http
});
sdk.start();

โหลดก่อนแอปด้วย node -r ./tracing.js app.js — เท่านี้ทุก HTTP request มี span เอง

gateway/app.js — เพิ่ม manual span ห่อ business logic:

const span = tracer.startSpan("checkout-flow");
const r = await fetch(`${ORDER_URL}/order`);   // fetch แนบ traceparent อัตโนมัติ
span.setAttribute("order.id", data.orderId);
span.end();

ขั้นที่ 2: รัน stack

cd docker/tracing/lab-traces-01
docker compose up -d --build
docker compose ps

ครั้งแรก build จะนานหน่อยเพราะต้อง npm install OTel packages (ค่อนข้างเยอะ) รอสักครู่

ขั้นที่ 3: ยิง request ให้เกิด trace

# ยิง checkout สัก 20 ครั้ง
for i in $(seq 1 20); do curl -s localhost:3000/checkout > /dev/null; echo "req $i"; done

แต่ละครั้งจะสร้าง trace ที่ผ่าน gateway → order-service → fake DB queries

ขั้นที่ 4: เปิด Jaeger ดู waterfall 🎉

เปิด http://localhost:16686

  1. ช่อง Service เลือก gateway
  2. กด Find Traces
  3. คลิกที่ trace อันหนึ่ง

คุณจะเห็น waterfall view แบบนี้ (ตามบทที่ 40):

checkout-flow                    [gateway]        ├──────────────────┤
 └─ GET /order                   [gateway→http]   │ ├───────────────┤
     └─ GET /order               [order-service]  │  ├──────────────┤
         ├─ SELECT inventory     [order-service]  │   ├────┤
         └─ INSERT order         [order-service]  │        ├───┤

สังเกตว่า span จาก สอง service ต่างกัน (gateway กับ order-service) อยู่ใน trace เดียวกัน เรียงตามเวลาจริง — นี่คือ context propagation ทำงาน! ทั้งที่เราไม่ได้เขียนโค้ดส่ง trace_id เองเลย OTel จัดการให้ผ่าน traceparent header

ขั้นที่ 5: หา trace ที่ช้าผิดปกติ

จำได้ว่า order-service จำลองความช้า 10% ของ request (หน่วง 500ms) ลองหา:

  1. ใน Jaeger ตั้ง Min Duration = 400ms แล้ว Find Traces
  2. เปิด trace ที่ช้า — จะเห็น span ที่กินเวลานานผิดปกติ ทำให้ระบุได้ทันทีว่าช้าตรงไหน

นี่คือ workflow จริงตอน debug: metric alert ว่า "p99 latency พุ่ง" (บทที่ 10) → เข้า Jaeger กรอง trace ที่ช้า → เห็น span ที่เป็นตัวการ → รู้ว่าต้องไปแก้ service ไหน (ลด MTTR จากบทที่ 00)

ขั้นที่ 6: สำรวจ attributes ของ span

คลิกที่ span แต่ละอันใน Jaeger เพื่อดู attributes (tags):

  • http.method, http.route, http.status_code (จาก auto-instrumentation)
  • db.system, db.statement (จาก fake DB span ที่เราใส่เอง)
  • order.id (attribute ที่เราเพิ่มใน manual span)

attribute พวกนี้คือ context ที่ทำให้ trace มีประโยชน์ตอน debug

ขั้นที่ 7 (คิดต่อ): เชื่อม 3 pillars

ลองจินตนาการต่อ (จะทำจริงในบทที่ 50):

  • ถ้าแต่ละ log ของ service ใส่ trace_id เดียวกับ span (บทที่ 30) → จาก Jaeger กระโดดไปอ่าน log ของ trace นั้นได้
  • ถ้า metric duration มี exemplar ลิงก์ไป trace → จากกราฟ latency คลิกไป trace ตัวอย่างได้เลย

ทำความสะอาด

docker compose down

✅ Checklist

  • เข้าใจว่า tracing.js + node -r ทำ auto-instrumentation ยังไง
  • เห็น trace ข้าม 2 service ใน waterfall เดียว
  • เข้าใจว่า context propagation ทำงานผ่าน traceparent header (ไม่ต้องเขียนเอง)
  • หา trace ที่ช้าด้วย Min Duration filter
  • อ่าน span attributes เพื่อ debug

สรุป

คุณเพิ่งเติม เสาที่สาม (Traces) ให้ repo ครบ! ตอนนี้คุณมีครบทั้ง 3 pillars:

  • 📈 Metrics — Prometheus + Grafana (Module 2)
  • 🪵 Logs — ELK (labs เดิมของคุณ + Module 3)
  • 🔬 Traces — OpenTelemetry + Jaeger (Module 4)

🎉 จบ Module 4! เข้าสู่ Module สุดท้าย — Hero level: เอา 3 เสามารวมร่างและใช้จริงตอนระบบเกิดเหตุ