📡 Obs · Zero→Hero
หน้าแรก/📈 2 · Metrics/Lab: Instrument แอป Node.js + Alert
🧪 LAB⏱ ~40 นาที

Lab: Instrument แอป Node.js + Alert

Lab ที่แล้วเราดู metric ของ เครื่อง คราวนี้เราจะ ฝัง metric ในโค้ดแอปเอง (RED metrics ตามบทที่ 22) แล้วตั้ง Alertmanager ให้เด้งเตือนเมื่อ error/latency พุ่ง — ครบวงจร instrument → scrape → alert

ไฟล์พร้อมรันที่ docker/prometheus/lab-metrics-02/ — มีแอป Node.js (app/app.js), alert rules (prometheus/rules/), และ Alertmanager config ให้แล้ว

Stack: แอป Node.js (prom-client) + Prometheus (+ rules) + Alertmanager + Grafana

ขั้นที่ 1: ดูโค้ดแอปก่อนรัน

เปิด app/app.js — จุดสำคัญคือ 3 ส่วนของ RED (จากบทที่ 22):

// R + E: นับ request แยกตาม method/route/status
const httpRequests = new client.Counter({
  name: "http_requests_total",
  labelNames: ["method", "route", "status"],   // low-cardinality!
  ...
});

// D: histogram วัด latency
const httpDuration = new client.Histogram({
  name: "http_request_duration_seconds",
  buckets: [0.005, 0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
  ...
});

แอปมี endpoint จำลองไว้ให้เล่น:

Endpoint พฤติกรรม ใช้ดูอะไร
/work เร็ว ปกติ baseline
/slow ช้า 200–1200ms latency p95/p99 พุ่ง
/error error 50% error rate + trigger alert
/metrics endpoint ที่ Prometheus scrape ดู metric ดิบ

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

cd docker/prometheus/lab-metrics-02
docker compose up -d --build      # --build เพราะต้อง build image ของแอป
docker compose ps

ขั้นที่ 3: ดู metric ดิบที่แอปพ่นออกมา

curl http://localhost:3000/metrics | grep http_requests_total

ตอนแรกอาจว่างเพราะยังไม่มี request — ลองยิงแอปสัก 2-3 ครั้งก่อน:

curl http://localhost:3000/work
curl http://localhost:3000/work
curl http://localhost:3000/metrics | grep http_requests_total

ตอนนี้จะเห็น:

http_requests_total{method="GET",route="/work",status="200"} 2

นี่คือ counter จริงที่คุณสร้างเองในโค้ด! สังเกต label route="/work" เป็น route pattern ไม่ใช่ raw URL — ตามหลักกัน cardinality explosion จากบทที่ 13

ขั้นที่ 4: สร้าง load เพื่อดู RED เคลื่อนไหว

รันคำสั่งนี้ทิ้งไว้เพื่อยิง request รัวๆ (จำลอง traffic จริง):

# ยิงผสมกัน work/slow/error ทุก 0.2 วินาที (กด Ctrl+C เพื่อหยุด)
while true; do
  curl -s localhost:3000/work  > /dev/null
  curl -s localhost:3000/slow  > /dev/null
  curl -s localhost:3000/error > /dev/null
  sleep 0.2
done

เปิด Prometheus (http://localhost:9090/graph) แล้วดู RED ครบสูตร:

# R — request rate ต่อวินาที
sum(rate(http_requests_total[1m]))

# E — error rate (เราทำเป็น recording rule ไว้แล้ว!)
job:http_error_rate:ratio5m

# D — p95 latency (recording rule)
job:http_p95_latency:seconds

job:http_error_rate:ratio5m คือ recording rule ที่เรานิยามไว้ใน prometheus/rules/app-rules.yml — Prometheus คำนวณให้ล่วงหน้า (บทที่ 21) ลองเทียบกับการเขียน query เต็มดู จะเห็นว่าสั้นลงเยอะ

ขั้นที่ 5: ดู alert rules

เปิด Status → Rules ใน Prometheus จะเห็น alert 3 ตัว (HighErrorRate, HighLatencyP95, TargetDown)

เพราะ /error fail 50% (เกิน threshold 5%) และ /slow ช้า (เกิน 500ms) รอสัก 30 วินาที (for: 30s) แล้วดูที่ Alerts tab — alert จะเปลี่ยนจาก PENDING (สีเหลือง) → FIRING (สีแดง)

PENDING  = เงื่อนไขเป็นจริงแล้ว แต่ยังไม่ครบเวลา for:
FIRING   = เป็นจริงครบเวลาแล้ว → ส่งไป Alertmanager

ขั้น PENDING → FIRING คือ for: ในบทที่ 14 ที่ทำงานจริง — มันกัน alert ที่เกิดจาก spike ชั่ววูบไม่ให้ปลุกคนโดยไม่จำเป็น

ขั้นที่ 6: ดู alert ที่ Alertmanager

เปิด http://localhost:9093 — Alertmanager จะแสดง alert ที่ FIRING โดย จัดกลุ่ม ตาม alertname/severity (ตาม group_by ใน config)

ลองสังเกต:

  • alert ถูกรวมกลุ่ม ไม่ได้ยิงทีละอันรัวๆ (ลด noise)
  • HighErrorRate มี severity: page, HighLatencyP95 มี severity: ticket — คนละความรุนแรง (บทที่ 14)

ใน lab นี้ Alertmanager ยังไม่ต่อปลายทางจริง (Slack/PagerDuty) — ดูวิธีต่อ Slack ได้ใน comment ของ alertmanager/alertmanager.yml แค่ใส่ webhook URL จริงก็ส่งเข้า Slack ได้เลย

ขั้นที่ 7: ทดสอบ alert หาย (resolve)

หยุด load generator (Ctrl+C) แล้วรอ — เมื่อ error rate ตกกลับต่ำกว่า 5% ต่อเนื่อง alert จะเปลี่ยนเป็น RESOLVED และหายไปจาก Alertmanager เอง นี่คือ lifecycle ครบวงจรของ alert

ขั้นที่ 8 (ท้าทาย): ทำ RED dashboard ใน Grafana

เปิด Grafana (http://localhost:3001, admin/admin) แล้วสร้าง dashboard 3 panel ตาม RED:

  1. Rate: sum(rate(http_requests_total[1m])) — unit: req/s
  2. Errors: job:http_error_rate:ratio5m — unit: percent (0.0-1.0), threshold แดงที่ 0.05
  3. Duration: job:http_p95_latency:seconds — unit: seconds, threshold แดงที่ 0.5

นี่คือ RED dashboard template จากบทที่ 11 & 23 ที่คุณเอาไปใช้กับทุก service ได้

ทำความสะอาด

docker compose down -v

✅ Checklist

  • เข้าใจโค้ด instrument (Counter + Histogram) ใน app.js
  • เห็น metric ดิบที่ /metrics ขยับตาม request
  • เขียน/ใช้ recording rule สำหรับ error rate + p95
  • เห็น alert เปลี่ยน PENDING → FIRING → RESOLVED
  • เข้าใจการจัดกลุ่ม + severity ใน Alertmanager
  • ทำ RED dashboard เอง

สรุป

คุณเพิ่งทำครบ pipeline ของ metrics pillar: instrument โค้ด → Prometheus scrape → recording/alert rules → Alertmanager → dashboard นี่คือสิ่งที่ทีม production ทำจริงทุกวัน 🎉

จบ Module 2! ต่อไปไป Module 3 — Logs ทบทวน ELK ที่คุณมีอยู่ให้เป็นระบบ แล้วต่อยอด