Featured image of post Observability: Logs vs. Metrics vs. Tracing — Mô hình tư duy 'Bộ dụng cụ Bác sĩ'

Observability: Logs vs. Metrics vs. Tracing — Mô hình tư duy 'Bộ dụng cụ Bác sĩ'

App chậm. Tại DB? Queue? Mạng? Hướng dẫn chuyên sâu về ba trụ cột observability và cách chúng phối hợp với nhau.

App production của bạn đang chậm. User phàn nàn. Sếp nhắn Slack.

Bạn SSH vào server và… nhìn chằm chằm vào màn hình.

Không có observability, debug production giống như bác sĩ chẩn đoán bệnh nhân mà không được nhìn, sờ, hay nói chuyện với họ. Bài viết này trao cho bạn bộ dụng cụ của Bác sĩ.


Phần 1: Nền tảng (Mô hình tư duy)

Bộ dụng cụ Bác sĩ

Bác sĩ có ba loại dụng cụ cho các câu hỏi khác nhau:

  • Ống nghe (Logs): “Để tôi NGHE bệnh nhân đang nói gì từng giây một.” Sự kiện thô. Có timestamp. Chi tiết. Ồn ào.
  • Bảng theo dõi sinh hiệu (Metrics): “Để tôi KIỂM TRA các con số quan trọng: nhịp tim, huyết áp, nhiệt độ.” Đã tổng hợp. Là số. Tốt cho dashboard.
  • X-Quang (Tracing): “Để tôi NHÌN THẤY bên trong và theo dõi đúng vấn đề này qua từng cơ quan.” Luồng request đầu cuối xuyên suốt các service.
Trụ cộtCâu hỏi trả lờiĐơn vịCông cụ
Logs“Chính xác chuyện gì đã xảy ra?”Text eventsDatadog, Loki, ELK Stack
Metrics“Hệ thống đang như thế nào nói chung?”Số liệu theo thời gianPrometheus, Grafana, Datadog
TracingRequest này bị chậm ở đâu?”Spans + TracesJaeger, Zipkin, OpenTelemetry

Phần 2: Điều tra (Đi sâu từng Trụ cột)

1. Logs — “Nhật ký của Bệnh nhân”

Log là bản ghi có timestamp về những gì đã xảy ra. Kỷ luật quan trọng nhất: structured logging (log có cấu trúc).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ❌ TỆ: Không có cấu trúc (khó query)
print(f"Lỗi xử lý đơn hàng cho user {user_id}")

# ✅ TỐT: JSON có cấu trúc (có thể tìm kiếm, lọc)
import structlog
log = structlog.get_logger()

log.error(
    "order_processing_failed",
    user_id=user_id,
    order_id=order_id,
    reason=str(e),
    duration_ms=123
)
# Output: {"event": "order_processing_failed", "user_id": 42, "order_id": 999, ...}

Log Levels (Dùng đúng!):

  • DEBUG: Chi tiết tỉ mỉ cho dev. Tắt ở production.
  • INFO: Hoạt động bình thường. “User 42 đăng nhập.”
  • WARNING: Có thể sắp có chuyện. “Ổ đĩa đầy 80%.”
  • ERROR: Thứ gì đó thất bại. “Thanh toán thất bại cho đơn 999.”
  • CRITICAL: App đang hấp hối. Người trực on-call thức dậy.

2. Metrics — “Bảng Sinh hiệu”

Metrics cho bạn biết xu hướng thay đổi theo thời gian. Bốn Tín hiệu Vàng (Google SRE):

  • Latency: Request mất bao lâu? (p50, p95, p99)
  • Traffic: Bao nhiêu request mỗi giây?
  • Errors: Bao nhiêu % request thất bại?
  • Saturation: Hệ thống đầy bao nhiêu? (CPU %, RAM %, độ sâu Queue)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Dùng Prometheus với Python
from prometheus_client import Counter, Histogram

REQUEST_LATENCY = Histogram("api_request_duration_seconds", "Độ trễ API")
ERROR_COUNT = Counter("api_errors_total", "Tổng lỗi API", ["endpoint"])

@REQUEST_LATENCY.time()  # Tự động đo thời gian hàm
def process_order(order_id):
    try:
        ...
    except Exception:
        ERROR_COUNT.labels(endpoint="/orders").inc()

3. Tracing — “Phim X-Quang”

Trong hệ thống microservices, một request user có thể đi qua 7 service. Nếu mất 2 giây, 2 giây đó ở đâu?

Tracing trả lời bằng Biểu đồ Thác nước (Waterfall):

1
2
3
4
5
6
Request: GET /checkout (2.0s tổng)
├── Auth Service (0.05s) ✅
├── Cart Service (0.08s) ✅
├── Inventory Service (1.6s) ← 🔴 NÚT CỔ CHAI
│   └── DB Query: SELECT ... (1.55s)  ← THỨ THỰC SỰ CHẬM
└── Payment Service (0.27s) ✅

OpenTelemetry là chuẩn mở. Viết một lần, gửi đến backend nào cũng được (Jaeger, Datadog,…):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def checkout(user_id):
    with tracer.start_as_current_span("checkout") as span:
        span.set_attribute("user.id", user_id)
        
        with tracer.start_as_current_span("fetch_cart"):
            cart = get_cart(user_id)  # Span này sẽ là con của span cha
        
        with tracer.start_as_current_span("process_payment"):
            charge(cart.total)

Phần 3: Chẩn đoán (Dùng Công cụ Nào?)

Vấn đềNhìn vào đâu trước?Tại sao
“Lỗi 500 cho user 42”LogsTìm thông báo lỗi và stack trace chính xác.
“API chậm từ 3 giờ chiều”MetricsTìm đỉnh P95 latency trên dashboard.
“Request này mất 2s”TracingXem Waterfall và tìm service nào chậm.
“Server bị sập”MetricsAlert CPU/Memory kích hoạt trước khi crash.

Phần 4: Giải pháp (Bộ Alerting)

Bạn không thể ngồi nhìn dashboard 24/7. Bạn cần alerts.

Alert tốt: “P99 latency vượt 2 giây trong 5 phút.” (Cụ thể, có thể hành động). Alert tệ: “CPU trên 50%.” (Mơ hồ, báo liên tục, gây alert fatigue).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Prometheus alerting rule
groups:
- name: api_alerts
  rules:
  - alert: HighLatencyP99
    # Báo alert nếu P99 latency > 2s trong 5 phút
    expr: histogram_quantile(0.99, api_request_duration_seconds_bucket) > 2
    for: 5m
    annotations:
      summary: "P99 latency của API đang ở mức nghiêm trọng"

Mô hình tư duy chốt hạ

1
2
3
4
5
6
7
Logs    -> Nhật ký Bệnh nhân. "Chuyện gì xảy ra? Khi nào? Chi tiết thế nào?"
Metrics -> Bảng Sinh hiệu. "Hệ thống đang biến đổi theo hướng nào?"
Tracing -> Phim X-Quang. "Request CỤ THỂ NÀY bị lỗi ở đâu?"

Dùng Logs để hiểu sự kiện.
Dùng Metrics để build dashboard và alert.
Dùng Tracing để debug giao dịch phân tán chậm.

Bạn cần cả ba. Log không có Metrics là bay mù. Metrics không có Tracing là biết mình bệnh nhưng không biết tại sao.

Được tạo với sự lười biếng tình yêu 🦥

Subscribe to My Newsletter