Tích hợp Sentry SDK Python: Tự động bắt lỗi production, giám sát APM và cảnh báo thời gian thực

Python tutorial - IT technology blog
Python tutorial - IT technology blog

Vấn đề thực tế: 2 giờ sáng, server production crash

2:17 AM. Điện thoại rung. Khách hàng ở Nhật đang báo lỗi, website không load được trang thanh toán.

Mình SSH vào server, chạy journalctl -u myapp -n 200, thấy một đống traceback. Nhưng câu hỏi thật sự là: lỗi này xảy ra từ bao giờ? Bao nhiêu user bị ảnh hưởng? Request nào trigger ra nó?

Log file có cả ngàn dòng. Grep thủ công mất 20 phút để xác định vấn đề. Lúc đó mới nhận ra mình hoàn toàn mù về trạng thái production — không có gì ngoài raw log và hy vọng user báo lỗi.

Đây là lúc mình bắt đầu nghiêm túc với Sentry.

Vấn đề không phải là thiếu log — mà là thiếu context

Mình có đủ log. Log đầy đến mức không đọc hết được. Vấn đề là thiếu context — và cách aggregate chúng thành thông tin có ý nghĩa. Với một incident production, đây là những thứ thực sự cần:

  • Stack trace đầy đủ, không phải 5 dòng cuối
  • Request URL, HTTP method, request body
  • User nào bị ảnh hưởng (user_id, email)
  • Môi trường: Python version, server name, deploy version nào
  • Lỗi này xảy ra lần đầu khi nào, tần suất thế nào
  • Có liên quan đến deploy gần nhất không

logging.error(str(e)) không cho bạn những thứ đó. Nó chỉ cho một dòng text.

Còn thứ khác nữa: performance monitoring. Trước khi có Sentry, mình không biết endpoint nào đang chậm hay query nào ngốn tài nguyên — cho đến khi user complain hoặc server OOM.

Hai hướng để giải quyết vấn đề này

Cách 1: Tự build hệ thống alert bằng logging + Slack

Nhiều team tự viết middleware gửi lỗi lên Slack:

import traceback
import requests

def notify_slack(error_msg):
    webhook = "https://hooks.slack.com/services/..."
    requests.post(webhook, json={"text": f"🚨 Error: {error_msg}"})

try:
    process_order(order_id)
except Exception as e:
    notify_slack(traceback.format_exc())
    raise

Cách này chạy được. Nhưng có vấn đề: không có deduplication — cùng 1 lỗi có thể trigger 1000 Slack message trong vài phút. Không có grouping theo type. Không có performance profiling. Và bạn tự maintain toàn bộ pipeline đó.

Cách 2: Dùng Sentry SDK

Sentry được xây dựng để làm đúng một việc: error monitoring. Có cả self-hosted miễn phí lẫn cloud. Tích hợp vào Python chỉ cần pip install và vài dòng code:

pip install sentry-sdk
import sentry_sdk

sentry_sdk.init(
    dsn="https://[email protected]/project-id",
    traces_sample_rate=1.0,
    environment="production",
    release="[email protected]",
)

Thế là xong bước đầu. Từ lúc này, mọi unhandled exception đều được Sentry bắt tự động.

Tích hợp Sentry từ cơ bản đến production-ready

1. Cấu hình đầy đủ với logging integration

import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration
import logging

logging_integration = LoggingIntegration(
    level=logging.INFO,        # Capture breadcrumb từ INFO
    event_level=logging.ERROR  # Chỉ tạo Sentry event từ ERROR
)

sentry_sdk.init(
    dsn="https://[email protected]/project-id",
    integrations=[logging_integration],
    traces_sample_rate=0.1,   # Sample 10% requests cho APM
    profiles_sample_rate=0.1,
    environment="production",
    release="[email protected]",
    send_default_pii=False,    # Không gửi PII
)

2. Gắn user context vào từng request

Khi debug lỗi, biết “ai gặp lỗi” quan trọng không kém biết “lỗi gì”:

from sentry_sdk import set_user, set_tag, set_context

# Gọi sau khi authenticate xong
def set_sentry_user(user):
    set_user({
        "id": user.id,
        "email": user.email,
        "username": user.username,
    })
    set_tag("plan", user.plan)
    set_tag("region", user.region)

# Custom context không giới hạn
set_context("order", {
    "order_id": order.id,
    "total": order.total,
    "items_count": len(order.items),
})

3. Capture exception thủ công với breadcrumbs

Breadcrumb ghi lại từng bước user thực hiện trước khi lỗi xảy ra. Nhìn vào incident với timeline đầy đủ, bạn tái hiện được bug chính xác thay vì đoán mò:

from sentry_sdk import add_breadcrumb, capture_exception

def process_payment(order_id: str, amount: float):
    add_breadcrumb(
        category="payment",
        message=f"Starting payment for order {order_id}",
        level="info",
        data={"amount": amount}
    )

    try:
        result = payment_gateway.charge(amount)
        add_breadcrumb(
            category="payment",
            message="Gateway responded",
            data={"status": result.status}
        )
        return result
    except PaymentGatewayError as e:
        capture_exception(e)  # Capture nhưng không re-raise
        return {"success": False, "error": "Payment failed"}
    except Exception as e:
        capture_exception(e)
        raise  # Lỗi không mong đợi — re-raise để alert

4. APM cho FastAPI và SQLAlchemy

Chỉ cần thêm vào danh sách integrations, Sentry tự instrument toàn bộ framework — không cần sửa từng endpoint:

from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration

sentry_sdk.init(
    dsn="...",
    integrations=[
        StarletteIntegration(transaction_style="endpoint"),
        FastApiIntegration(transaction_style="endpoint"),
        SqlalchemyIntegration(),  # Tự động trace DB query
    ],
    traces_sample_rate=0.05,  # 5% cho app traffic cao
)

Sau khi setup, Sentry hiển thị waterfall chart cho từng request: thời gian xử lý, N+1 query, slow endpoint. Lần đầu nhìn vào dashboard, mình phát hiện ra một endpoint đang thực hiện 47 queries riêng lẻ thay vì 1 query JOIN — cái mà log không bao giờ cho bạn thấy.

5. Lọc event để tránh alert noise

Không phải mọi exception đều cần wake up lúc 2 AM. Lỗi 404 từ bot scanner, timeout bình thường hay validation error của user thì không cần:

import re

def before_send(event, hint):
    # Bỏ qua health check endpoint
    if "request" in event:
        url = event["request"].get("url", "")
        if re.search(r"/(health|ping|metrics)", url):
            return None  # None = không gửi event lên Sentry

    # Bỏ qua một số exception type cụ thể
    if "exc_info" in hint:
        exc_type, exc_value, _ = hint["exc_info"]
        if isinstance(exc_value, (KeyboardInterrupt, BrokenPipeError)):
            return None

    return event

sentry_sdk.init(
    dsn="...",
    before_send=before_send,
)

Khi cần viết pattern lọc URL phức tạp hơn trong before_send, mình hay dùng regex. Để test nhanh pattern trước khi đưa vào code, mình dùng regex tester tại toolcraft.app/vi/tools/developer/regex-tester — chạy ngay trên trình duyệt, không cần cài gì, tiết kiệm khá nhiều thời gian debug.

6. Release tracking kết hợp CI/CD

Với release tracking, Sentry biết lỗi xuất hiện từ commit nào, ai thay đổi dòng code đó:

# Trong CI pipeline, sau khi deploy
export SENTRY_AUTH_TOKEN=your-auth-token
export SENTRY_ORG=your-org
export SENTRY_PROJECT=your-project

pip install sentry-cli
sentry-cli releases new "myapp@${GIT_SHA}"
sentry-cli releases set-commits "myapp@${GIT_SHA}" --auto
sentry-cli releases finalize "myapp@${GIT_SHA}"

7. Alert rules trên dashboard

Trên Sentry dashboard, vào Alerts → Create Alert Rule:

  • Issue Alert: Trigger khi lỗi mới xuất hiện lần đầu, hoặc regression sau khi đã resolve
  • Metric Alert: Trigger khi error rate vượt ngưỡng (VD: >5% requests lỗi trong 5 phút)
  • Performance Alert: Trigger khi P95 latency của một endpoint tăng đột biến

Phần khó nhất không phải cài đặt mà là chọn ngưỡng đúng: quá nhạy thì alert fatigue, quá lỏng thì miss incident thật.

8. Self-hosted cho team muốn kiểm soát data

# Yêu cầu ~4GB RAM
git clone https://github.com/getsentry/self-hosted.git
cd self-hosted
./install.sh
docker-compose up -d

Self-hosted phù hợp nếu có compliance requirement. Cloud plan free cho phép 5,000 errors/tháng — đủ cho project nhỏ và vừa.

Sau lần incident 2 giờ sáng đó, mình setup Sentry cho toàn bộ production apps. Lần tiếp theo có lỗi, Sentry push Slack notification với đầy đủ context trong vài giây — biết ngay user nào bị, endpoint nào, deploy nào gây ra. MTTR giảm từ 45 phút xuống còn 8 phút. Đó là sự khác biệt giữa reactive (đợi user báo) và proactive (biết trước khi user biết).

Share: