12/04/2026 18:16น.

Golang The Series EP 128: Logging, Monitoring และ Observability – เปลี่ยนกล่องดำให้เป็นกล่องแก้ว
#Observability
#Golang
#Go
#Monitoring
#Logging
ยินดีต้อนรับชาว Gopher ทุกท่านเข้าสู่ EP 128 ครับ! ในตอนที่แล้ว (EP 127) เราได้เรียนรู้วิธีติดตั้ง Circuit Breaker เพื่อป้องกันระบบล่มแบบโดมิโน่ไปแล้ว ซึ่งนั่นคือการสร้าง "กลไกป้องกัน"
แต่ในโลกความเป็นจริง คำถามที่วิศวกรซอฟต์แวร์ต้องตอบให้ได้คือ: "ถ้าเบรกเกอร์ตัดตอนตี 2 อะไรคือสาเหตุที่แท้จริง?" หรือ "เราจะรู้ได้อย่างไรว่าระบบเริ่มทำงานผิดปกติ ก่อนที่ผู้ใช้งานจะเริ่มบ่น?"
วันนี้เราจะมาเจาะลึก 3 ประสานที่จะเปลี่ยนระบบของคุณจาก Black Box (กล่องดำที่มองไม่เห็นข้างใน) ให้กลายเป็น Glass Box (กล่องแก้วที่โปร่งใส) ด้วย Logging, Monitoring และ Observability ครับ
1. Monitoring vs. Observability: ต่างกันอย่างไร?
หลายคนมักใช้สองคำนี้สลับกัน แต่ในเชิงวิศวกรรมมีความหมายที่ต่างกันอย่างมีนัยสำคัญ:
- Monitoring (การเฝ้าสังเกต): เน้นตอบคำถามว่า "Is it working?" (ระบบยังปกติไหม?) เป็นการดูค่าจากภายนอก เช่น CPU Usage, Memory, หรือ HTTP Status 200/500 ถ้าค่าเหล่านี้ผิดปกติ ระบบจะแจ้งเตือน (Alert) ทันที
- Observability (ความสามารถในการสังเกต): เน้นตอบคำถามว่า "Why is it happening?" (ทำไมมันถึงเกิดปัญหานั้น?) โดยอาศัยข้อมูลดิบที่ระบบส่งออกมา (Telemetry Data) เพื่อให้เราสืบสวนหาต้นตอ (Root Cause) ของปัญหาที่ซับซ้อนได้โดยไม่ต้องรันโค้ดใหม่หรือ Deploy แก้ไขเพื่อดู Log เพิ่ม
2. เสาหลักที่ 1: Structured Logging ด้วย log/slog
การใช้ fmt.Println หรือ log.Printf เป็นสิ่งที่ควรหลีกเลี่ยงบน Production เพราะมันได้แค่ "ข้อความ" ที่โปรแกรมอื่นอ่านยาก ในระดับ Enterprise เราใช้ Structured Logging (รูปแบบ JSON) เพื่อให้ Centralized Log (เช่น Grafana Loki, ELK หรือ Google Cloud Logging) สามารถ Query ข้อมูลได้แม่นยำ
ใน Go 1.21 เรามี Library มาตรฐานคือ log/slog ที่ออกแบบมาเพื่อประสิทธิภาพและความง่าย:
Go
package main
import (
"context"
"log/slog"
"os"
)
func main() {
// 1. ตั้งค่า Handler ให้พ่น Log เป็น JSON ออกทาง Standard Out
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug, // กำหนดระดับ Log
})
logger := slog.New(handler)
// ตั้งเป็น Default เพื่อเรียกใช้ผ่าน slog.Info ได้ทันที
slog.SetDefault(logger)
ctx := context.Background()
userID := "user_99"
traceID := "tx-abc-123"
// 2. การเก็บข้อมูลแบบ Key-Value ที่ค้นหาง่าย
slog.LogAttrs(ctx, slog.LevelInfo, "Process Payment Success",
slog.String("user_id", userID),
slog.String("trace_id", traceID),
slog.Float64("amount", 2500.75),
slog.String("currency", "THB"),
)
}
ทำไมต้อง JSON?
เพราะเมื่อเกิดปัญหา คุณสามารถค้นหา { "user_id": "user_99" } ในระบบจัดการ Log แล้วจะเห็น Timeline ของ User คนนี้ทั้งหมดทันที ไม่ต้องนั่งใช้ grep ไล่หาจาก Text ไฟล์ขนาดหลาย GB
3. เสาหลักที่ 2: Metrics และ "The 4 Golden Signals"
Metrics คือการเก็บข้อมูลเชิงปริมาณ (ตัวเลข) ในรูปแบบ Time-series เพื่อสร้างกราฟ Dashboard เรามักใช้ Prometheus เป็นมาตรฐาน โดยเน้นตัวชี้วัด 4 อย่าง (อ้างอิงจาก Google SRE Book):
- Latency: เวลาที่ใช้ประมวลผล (หน่วยเป็น ms)
- Traffic: ปริมาณความต้องการ (เช่น Request per second)
- Errors: อัตราความล้มเหลว (เช่น HTTP 5xx Rate)
- Saturation: ความอิ่มตัว (ทรัพยากรเหลือเท่าไหร่ เช่น Disk หรือ Memory)
ตัวอย่างการทำ Instrumentation ด้วย Prometheus ใน Go:
Go
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
// Counter: ค่าที่เพิ่มขึ้นเรื่อยๆ (ห้ามลดลง) เช่น จำนวน Request
httpRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "status", "path"},
)
)
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ประมวลผล...
next.ServeHTTP(w, r)
// เก็บ Metric แยกตาม Method และ Status Code
httpRequestsTotal.WithLabelValues(r.Method, "200", r.URL.Path).Inc()
})
}
4. เสาหลักที่ 3: Distributed Tracing (ตามรอย Request)
ในโลกของ Microservices หนึ่ง Request อาจวิ่งผ่าน 5-10 Services หาก Service ท้ายๆ ทำงานช้า เราจะรู้ได้อย่างไร?
Distributed Tracing (เช่น OpenTelemetry) จะสร้าง Trace ID ชุดเดียวที่ติดตัว Request ไปทุกที่ ทำให้เราเห็น "Gantt Chart" ของการเรียกใช้งานแต่ละจุด (Span) อย่างชัดเจน
Pro Tip: การผูก Trace ID ไว้ใน Log (ในหัวข้อที่ 2) จะช่วยให้คุณ "คลิก" จากจุดที่ระบบช้าในกราฟ Tracing เพื่อกระโดดไปดู Log เฉพาะของ Transaction นั้นได้ทันที!
5. กลยุทธ์การสร้าง Dashboard และ Alerting
Dashboard ที่ดีไม่ใช่ Dashboard ที่มีกราฟเยอะที่สุด แต่คือ Dashboard ที่ "ตอบคำถามได้เร็วที่สุด"
- Top-Level View: แสดงค่า "Health" โดยรวม (แดง/เขียว)
- Actionable Alerts: การแจ้งเตือนต้องมีความหมาย เช่น "Error Rate > 5% ภายใน 2 นาที" ไม่ควรเตือนเรื่องที่แก้เองไม่ได้ หรือเรื่องที่ไม่ได้ส่งผลกระทบต่อ User
- Correlation: ต้องสามารถเจาะลึก (Drill down) จากระดับสูงไปหาระดับต่ำได้ เช่น จากกราฟ Latency ไปหา Trace ID ที่ช้าที่สุด
สรุป
Logging, Monitoring และ Observability ไม่ใช่ "ส่วนเสริม" แต่มันคือ "หัวใจ" ของงานวิศวกรรมที่ช่วยลดค่า MTTR (Mean Time To Recovery) หรือเวลาที่ใช้ในการกู้คืนระบบให้สั้นที่สุด เพราะในโลกของ Software ปัญหาจะเกิดขึ้นแน่นอน (Everything fails all the time) หน้าที่ของเราคือทำให้มองเห็นมันให้เร็วที่สุดครับ
ในตอนต่อไป (EP 129): เราจะนำความรู้เหล่านี้มาต่อยอดในการออกแบบระบบให้มีความอึดระดับพระกาฬกับ High Availability & Failover Design – วิธีรับมือเมื่อ Server ระเบิดไปครึ่งหนึ่งแต่ระบบยังต้องรันต่อได้! ห้ามพลาดครับ