พื้นฐาน Logging
Log เป็นเสาที่คุณมีอยู่แล้ว (ELK) แต่ก่อนจะทบทวนสถาปัตยกรรม เรามาปูพื้นฐานว่า log ที่ดี หน้าตาเป็นยังไง เพราะ ELK ที่เก่งแค่ไหนก็ช่วยไม่ได้ถ้า log ต้นทางมั่ว
Log Levels — จัดระดับความสำคัญ
ทุก log ควรมี level เพื่อบอกความรุนแรง และให้ filter ได้ ระดับมาตรฐาน (เรียงจากเบาไปหนัก):
| Level | ใช้เมื่อ | ตัวอย่าง | ควร alert? |
|---|---|---|---|
| TRACE | ละเอียดยิบ debug ลึก | "เข้าฟังก์ชัน X ด้วย arg=..." | ❌ |
| DEBUG | ข้อมูลช่วย dev ตอน debug | "cache miss สำหรับ key=..." | ❌ |
| INFO | เหตุการณ์ปกติที่ควรรู้ | "user 889 สั่งซื้อสำเร็จ" | ❌ |
| WARN | ผิดปกติแต่ยังไปต่อได้ | "retry ครั้งที่ 2, DB ตอบช้า" | บางที |
| ERROR | งานนี้ล้มเหลว | "ชำระเงินไม่สำเร็จ: card declined" | ✅ มักใช่ |
| FATAL | ระบบไปต่อไม่ได้ ต้องตาย | "ต่อ DB ไม่ได้ตอน startup" | ✅ ใช่ |
ตั้งค่า level ที่ปล่อยออกได้ตาม environment: production ปกติปล่อย INFO ขึ้นไป (DEBUG/TRACE ปิดไว้เพราะเยอะและแพง) แต่เปิด DEBUG ชั่วคราวได้เมื่อต้อง debug ปัญหาเฉพาะ
อย่าใช้ level มั่ว — log ที่ตั้งเป็น ERROR ทั้งที่ไม่ใช่ error จริง จะสร้าง "ERROR fatigue" แบบเดียวกับ alert fatigue (บทที่ 14) คนจะเลิกเชื่อ ERROR log
Structured Logging — หัวใจของ log ที่ค้นได้
นี่คือเรื่องสำคัญที่สุดของบทนี้ เทียบ log 2 แบบ:
❌ Unstructured (ข้อความดิบ) — คนอ่านออก แต่เครื่อง parse ยาก:
2026-08-20 10:30:04 ERROR user 889 failed to pay order 5512 amount 1500 card declined
✅ Structured (JSON) — เครื่อง query ได้ทันที:
{
"timestamp": "2026-08-20T10:30:04Z",
"level": "error",
"service": "payment-api",
"event": "payment_failed",
"user_id": "889",
"order_id": "5512",
"amount": 1500,
"reason": "card_declined"
}
ทำไม structured ชนะขาด:
- ค้นได้แม่นยำ — ใน Kibana ค้น
user_id: "889" AND level: "error"ได้ทันที ไม่ต้อง regex มั่ว - aggregate ได้ — นับ
payment_failedแยกตามreasonได้เลย - ไม่พังเมื่อข้อความมี format แปลก — ไม่ต้องพึ่ง grok pattern ที่เปราะ
นี่คือเหตุผลที่ lab ELK ของคุณ (lab-05-structured-nestjs) ขยับมาใช้ JSON logging — และทำไม logstash.conf ใน lab นั้นใช้
jsonfilter แทนgrokที่ซับซ้อน โครงสร้างที่ต้นทางดี ทำให้ปลายทางง่ายลงมหาศาล
Correlation ID — ร้อย log ของ request เดียวเข้าด้วยกัน
ในระบบที่ 1 request วิ่งผ่านหลาย service (หรือหลาย log line) เราต้องการ ตัวเชื่อม เพื่อตามรอย request เดียวได้:
{ "trace_id": "a1b2c3", "service": "gateway", "msg": "รับ request" }
{ "trace_id": "a1b2c3", "service": "auth", "msg": "ยืนยันตัวตนผ่าน" }
{ "trace_id": "a1b2c3", "service": "payment", "msg": "charge failed", "level": "error" }
ค้น trace_id: "a1b2c3" ก็เห็น ทั้งเส้นทาง ของ request นั้นเรียงกัน — นี่คือสะพานเชื่อม log เข้ากับ traces (Module 4) และเป็นหัวใจของการ correlate 3 pillars (บทที่ 50)
สร้าง
trace_idที่ edge (gateway/first service) แล้วส่งต่อผ่าน HTTP header (traceparent) ให้ทุก service log ด้วย id เดียวกัน — OpenTelemetry (บทที่ 41) ทำเรื่องนี้ให้อัตโนมัติ
ของที่ "ห้าม" log เด็ดขาด
อย่า log ข้อมูลอ่อนไหว — เพราะ log มักถูกเก็บนาน, ส่งข้าม network, และเข้าถึงได้หลายคน ห้าม log:
- รหัสผ่าน, token, API key, session cookie
- เลขบัตรเครดิตเต็ม, CVV
- PII ตามกฎหมาย (เลขบัตรประชาชน, ข้อมูลสุขภาพ) — ระวัง PDPA/GDPR
- ข้อมูลส่วนตัวที่ไม่จำเป็น
ถ้าจำเป็นต้องอ้างถึง ให้ mask (
****1234) หรือ hash แทน การเผลอ log ของพวกนี้เป็นสาเหตุ data breach ที่พบบ่อยมาก
ปริมาณและต้นทุน — log แพงกว่าที่คิด
จำจากบทที่ 01: log ใหญ่และแพงกว่า metric เป็นพันเท่า ดังนั้น:
- อย่า log ทุกอย่างใน loop — log ในลูปที่วิ่งล้านรอบ = ระเบิด volume + ค่าใช้จ่าย
- Sampling — สำหรับ event ที่เยอะมาก log แค่บางส่วน (เช่น 1%) ก็พอเห็น pattern
- ตั้ง retention — log ปกติเก็บ 7–30 วันก็พอ (ต่างจาก metric ที่เก็บเป็นปีได้เพราะเล็ก)
- แยก level — เก็บ ERROR นานกว่า DEBUG
สรุป
- ใช้ log levels ให้ถูก (INFO ขึ้นไปใน prod, ERROR/FATAL คือของที่ควร alert)
- Structured logging (JSON) คือหัวใจ — ค้นได้ aggregate ได้ ไม่ต้องพึ่ง grok เปราะๆ
- ใส่ correlation/trace ID เพื่อร้อย log ของ request เดียว (สะพานสู่ traces)
- ห้าม log ข้อมูลอ่อนไหว (password, token, PII) — mask/hash แทน
- log แพง — คุม volume ด้วย sampling + retention
บทหน้า: ทบทวน สถาปัตยกรรม ELK และโยงเข้ากับ lab 01–06 ที่คุณทำมาให้เป็นภาพเดียว