Lập trình 22/09/2026 8 phút

Structured logging với slog: vì sao log chuỗi tự do là món nợ kỹ thuật bạn trả lúc 3 giờ sáng

Lúc sự cố xảy ra, bạn không đọc log — bạn truy vấn nó. Và log chuỗi tự do (fmt.Printf) không truy vấn được: mỗi dòng một định dạng, muốn lọc phải viết regex. Bài này đo thật với log/slog của Go 1.23: cùng một sự kiện in ra chuỗi tự do và JSON có cấu trúc, rồi dùng jq lọc 1000 dòng log theo nhiều field (đếm ERROR theo service, tính latency trung bình). Kèm số đo chi phí thật — và một sự thật ngược đời: log chuỗi nhanh hơn slog gần 1.7 lần.

Lập trình 22/09/2026 7 phút

Log correlation: gắn trace_id vào context để dựng lại hành trình một request giữa hàng nghìn dòng log

Có log JSON đẹp rồi, nhưng giữa 150 dòng log của 50 request chạy song song, đâu là những dòng của riêng một request? Nếu không có ID chung, chúng đan xen theo lịch chạy goroutine và bạn không tách nổi. Bài này đo thật trong Go: một slog.Handler tùy biến tự gắn trace_id lấy từ context, để mỗi request mang một ID xuyên suốt; rồi một câu jq lọc đúng 3 bước của request trace-0007 giữa 150 dòng — và mọi trace_id đều xuất hiện đúng 3 lần, không sót không lẫn.

Lập trình 22/09/2026 6 phút

Sampling: head sampling 1% bỏ sót 99% lỗi, error-biased giữ 4% mà bắt 100% lỗi

Trace và log mỗi request thì đúng nhất, nhưng hàng triệu request/ngày là khối dữ liệu không kham nổi. Sampling giảm khối lượng — nhưng sampling ngẫu nhiên (head) bỏ mù đúng thứ cần thấy: lỗi hiếm. Bài này đo thật trên 100.000 trace: head sampling 1% chỉ bắt 14/1029 lỗi (bỏ sót 99%); error-biased sampling giữ tổng cộng chỉ 4% mà bắt trọn 1029/1029 lỗi. Cùng bàn cái giá của tail sampling và vì sao metric không sample.

Lập trình 22/09/2026 7 phút

Structured logging: vì sao log JSON đánh bại log văn bản, và trace_id nối log với trace

Log văn bản thuần đọc bằng mắt thì được, nhưng máy khó truy vấn — grep với regex mong manh. Bài này chạy thật slog của Go in log JSON có cấu trúc, rồi dùng jq lọc theo level, theo độ trễ, tổng hợp doanh thu ngay trên log. Và cú chốt: gắn trace_id thật từ OpenTelemetry vào mỗi dòng log — thấy lỗi trong log là nhảy thẳng tới đúng trace trong Jaeger, khớp đã kiểm chứng.