Cảnh báo cuộc gọi Sentry cho lỗi làm sập production

Sentry không có hành động gọi điện. Đưa issue alert qua webhook để chỉ những lỗi làm sập production mới đổ chuông: cách cài đặt, payload và cách lọc.

Cập nhật

Mục lục

Sentry không thể gọi điện cho bạn. Nó gửi được email, đăng lên Slack, hoặc chuyển cảnh báo cho PagerDuty — nhưng không có hành động thoại tích hợp sẵn. Cách để có được điều đó mà không phải mua một nền tảng quản lý sự cố là gửi issue alert của Sentry tới một webhook biết đổ chuông: tạo một internal integration, trỏ nó tới kênh cuộc gọi của Echobell, rồi đặt một bộ lọc phía trước để chỉ những lỗi thực sự làm sập production được đi qua.

Bài này đi hết cả đường dẫn: integration, quy tắc cảnh báo, payload mà Sentry thực sự gửi, các template đọc payload đó, và hai cái bẫy khiến người ta bỏ cuộc.

Vì sao Sentry tự nó không làm điện thoại đổ chuông

Các hành động của issue alert trong Sentry gồm thông báo (email, Slack, Discord, Microsoft Teams), tạo ticket (Jira, GitHub, Azure DevOps) và chuyển giao cho sản phẩm paging (PagerDuty, Opsgenie). Cái nào cũng kết thúc ở một màn hình mà bạn phải đang nhìn vào, hoặc ở một chỗ ngồi trả phí trên nền tảng khác.

Lúc 14 giờ thì không sao. Lúc 3 giờ sáng, một tin nhắn Slack không khác gì im lặng, còn thông báo đẩy thì thua chế độ Không làm phiền. Với nhóm nhỏ những lỗi mà chậm hai tiếng là mất tiền thật — checkout trả về 500, xác thực từ chối mọi lượt đăng nhập, worker âm thầm đánh rơi job — bạn cần một thiết bị biết reo.

Webhook là chỗ nối. Sentry có thể gọi một endpoint HTTPS bất kỳ như một hành động của quy tắc cảnh báo; Echobell biến yêu cầu HTTP đó thành cảnh báo kiểu cuộc gọi, xuyên qua chế độ Tập trung của iOS.

Bạn cần những gì

  • Một tổ chức Sentry mà bạn vào được Settings → Developer Settings (owner hoặc manager)
  • Đã cài Echobell (App Store / Google Play)
  • Năm phút

Phía bạn không cần bất cứ thứ gì có thể truy cập từ internet. Sentry là bên gửi yêu cầu đi; bạn chỉ nhận.

Bước 1 — Tạo một kênh biết đổ chuông

Trong Echobell, tạo một kênh và đặt loại thông báo là Cuộc gọi. Đây chính là điểm mấu chốt: kênh cuộc gọi hành xử như một cuộc gọi đến chứ không phải thông báo đẩy, nên nó xuyên qua chế độ Tập trung và Không làm phiền.

Hãy đặt template sao cho lúc 3 giờ sáng vẫn hiểu được. Payload của Sentry lồng rất sâu, nên đường dẫn biến dài hơn bình thường:

Tiêu đề: {{data.event.level}}: {{data.event.metadata.type}}
Nội dung: {{data.event.title}} — {{data.event.culprit}}

Đặt template liên kết trong phần cài đặt nâng cao để chạm vào thông báo là mở đúng issue:

{{data.event.web_url}}

Sao chép URL webhook trong màn hình chi tiết kênh. Nó có dạng:

https://hook.echobell.one/t/<channel-token>

Bước 2 — Tạo internal integration trong Sentry

Sentry chỉ cung cấp webhook như một hành động của quy tắc cảnh báo thông qua integration, nên bạn phải tạo một cái. Đó là một biểu mẫu chứ không phải một dịch vụ — bạn không viết dòng mã nào.

  1. Vào Settings → Developer Settings → Custom Integrations
  2. Create New Integration → Internal Integration
  3. Name: Echobell (đây là tên bạn sẽ chọn trong quy tắc)
  4. Webhook URL: URL kênh ở Bước 1
  5. Bật công tắc Alert Rule Action
  6. Permissions: Issue & Event → Read là đủ
  7. Trong mục Webhooks, để tất cả ô không tích — xem cái bẫy bên dưới
  8. Lưu lại

Internal integration chỉ dùng trong tổ chức của bạn và tự cài đặt. Token nó sinh ra không cần dùng cho thiết lập này.

Bước 3 — Thêm integration làm hành động của quy tắc

Vào Alerts → Create Alert → Issue Alert, hoặc sửa một quy tắc sẵn có.

Ở phần Then perform these actions, thêm Send a notification via an integration và chọn Echobell.

Đặt Action interval — bộ hãm "nếu cảnh báo này đã kích hoạt nhiều hơn một lần" — tối thiểu 30 minutes. Mặc định là gửi mỗi lần kích hoạt, và một lỗi bắn 400 lần mỗi phút sẽ quay số của bạn cho tới khi bạn tắt hẳn.

Lưu lại, rồi chạy thử quy tắc để thấy một payload thật đến nơi trước khi tin tưởng nó.

Bước 4 — Biết thứ thực sự gửi tới là gì

Đây là chỗ phần lớn thiết lập vỡ, vì payload không có hình dạng như bạn đoán. Sentry bọc mọi thứ lại:

{
  "action": "triggered",
  "actor": { "id": "sentry", "name": "Sentry", "type": "application" },
  "data": {
    "event": {
      "event_id": "e4874d664c3540c1a32eab185f12c5ab",
      "level": "error",
      "title": "ReferenceError: heck is not defined",
      "culprit": "?(<anonymous>)",
      "platform": "javascript",
      "project": 1,
      "release": null,
      "metadata": { "type": "ReferenceError", "value": "heck is not defined" },
      "tags": [["level", "error"], ["browser", "Chrome 75.0.3770"]],
      "issue_id": "1117540176",
      "issue_url": "https://sentry.io/api/0/issues/1117540176/",
      "web_url": "https://sentry.io/organizations/test-org/issues/1117540176/events/e4874.../"
    },
    "triggered_rule": "Very Important Alert!"
  },
  "installation": { "uuid": "a8e5d2..." }
}

Bốn điều nên biết trước khi viết dù chỉ một template:

  • Mọi thứ hữu ích nằm dưới data.event. {{title}} không hiển thị gì; {{data.event.title}} mới ra lỗi.
  • data.event.project là ID dạng số, không phải slug. Muốn tên dự án đọc được trong thông báo thì viết thẳng vào template tiêu đề và dùng mỗi dự án một kênh.
  • Không có trường environment. Môi trường nằm trong data.event.tags dưới dạng cặp ["environment", "production"], và vị trí của nó trong mảng không cố định — đừng truy cập theo chỉ số. Hãy lọc môi trường trong quy tắc Sentry (Bước 5).
  • data.triggered_rule là tên quy tắc. Hữu ích trong phần nội dung khi một kênh phục vụ nhiều quy tắc.

Header Sentry-Hook-Resource có giá trị event_alert với issue alert. Bạn có thể bắt buộc nó trong điều kiện kênh để không thứ gì khác làm kênh đổ chuông được:

header["sentry-hook-resource"] == "event_alert"

Bước 5 — Thu hẹp tới mức xứng đáng một cuộc gọi

Một kênh cuộc gọi reo với mọi issue mới còn tệ hơn là không có kênh nào: trong một tuần bạn sẽ tắt tiếng nó, và rồi nó sẽ không reo vào đúng lần quan trọng. Hãy lọc ở hai nơi.

Trong Sentry, dùng conditions và filters của quy tắc:

Mục tiêuCấu hình quy tắc
Chỉ productionĐặt Environment của quy tắc là production
Chỉ sự cố thậtFilter: The event's level equals fatal (hoặc error)
Bỏ qua trồi sụt nhất thờiCondition: The issue is seen more than 25 times in 1 hour
Chỉ một luồng quan trọngFilter: The event's tags match transaction contains /checkout
Chỉ lỗi tái phátCondition: A resolved issue changes state from resolved to unresolved

Trong Echobell, dùng điều kiện kênh như lưới an toàn cho những gì Sentry không diễn đạt được, hoặc cho thay đổi mà hôm nay bạn chưa triển khai được:

data.event.level == "fatal" || data.event.level == "error"

Lọc mức độ nghiêm trọng trong quy tắc Sentry thường tốt hơn, vì phần hãm tần suất cũng nằm ở đó. Lọc trong Echobell tốt hơn khi bạn muốn hai mức khẩn cấp từ cùng một quy tắc.

Bước 6 — Cho cảnh báo nhẹ một cánh cửa yên tĩnh hơn

Ý nghĩa của việc phân tầng là để cuộc gọi giữ được trọng lượng của nó. Tạo kênh Echobell thứ hai loại Nhạy thời gian (Time Sensitive), thêm quy tắc Sentry thứ hai với ngưỡng thấp hơn, rồi trỏ nó tới một internal integration thứ hai (mỗi integration chỉ giữ một URL webhook, nên kênh thứ hai cần integration thứ hai).

Một thiết lập sống sót qua một tuần thật sự trông đại khái thế này:

Quy tắc SentryMức / ngưỡngKênh EchobellHành vi
prod-fatalfatal, productionCuộc gọiReo xuyên chế độ Tập trung
prod-error-spikeerror, hơn 100 lần trong 1 giờNhạy thời gianHiện trên màn hình khóa, không reo
new-issue-digestmọi issue mớiThườngThông báo đẩy bình thường, đọc lúc rảnh

Chỉ reo ngoài giờ làm việc

Ban ngày bạn vốn đã nhìn Sentry rồi. Echobell cung cấp cho điều kiện các biến thời gian hệ thống theo UTC, nên một kênh có thể hành xử khác nhau theo giờ mà không cần quy tắc Sentry thứ hai:

data.event.level == "fatal" && (hour >= 17 || hour < 9)

Thêm kiểm tra thứ trong tuần nếu cuối tuần của bạn thật sự là ngày nghỉ:

data.event.level == "fatal" && (hour >= 17 || hour < 9 || dayOfWeek == 0 || dayOfWeek == 6)

Tất cả đều theo UTC, nên hãy quy đổi từ múi giờ của bạn trước khi chốt con số. Tài liệu tham khảo điều kiện có danh sách biến đầy đủ.

Hai cái bẫy

Bẫy 1: tích các ô Webhooks. Một internal integration có hai đường webhook độc lập. Công tắc Alert Rule Action khiến integration hiện ra để chọn trong quy tắc cảnh báo — đó là cái bạn cần. Còn các ô Webhooks (issue, error, comment) sẽ đăng ký cho bạn mọi sự kiện của tài nguyên đó: mọi issue được tạo, giải quyết, gán, lưu trữ hay bỏ qua, trên toàn bộ tổ chức. Tích issue và điện thoại sẽ reo mỗi khi đồng nghiệp đóng một vấn đề. Để trống hết, và chỉ quy tắc cảnh báo của bạn mới kích hoạt webhook.

Bẫy 2: dùng plugin Webhooks cũ. Plugin cũ theo từng dự án Legacy Integrations → WebHooks vẫn còn và vẫn chạy, và trông như một lối tắt vì bạn dán được URL mà không cần tạo integration. Nhưng payload của nó có hình dạng khác, phẳng hơn, các yêu cầu không được ký, và chính Sentry cũng hướng thiết lập mới sang chỗ khác. Nếu dùng nó, template của bạn sẽ cần đường dẫn biến khác với ở trên. Hãy dùng internal integration.

Kích thước payload, bão lỗi và cắt bớt

Ba giới hạn đáng biết trước khi có chuyện ở quy mô lớn:

  • Thân yêu cầu 1 MiB. Echobell từ chối thân yêu cầu kích hoạt lớn hơn 1 MiB bằng HTTP 413. Payload của Sentry mang theo toàn bộ stack trace và ngữ cảnh yêu cầu, thường rơi vào vài chục kilobyte — nhưng một sự kiện với thân yêu cầu lớn có thể tiệm cận ngưỡng. Phía Sentry không có núm max_alerts, nên cách giảm thiểu là làm sạch các thân yêu cầu lớn trong beforeSend của SDK, điều mà vì lý do riêng tư bạn cũng nên làm.
  • 120 yêu cầu mỗi phút cho mỗi token. Vượt qua đó, trigger trả về 429 kèm RATE_LIMIT_EXCEEDED và một Retry-After. Thứ giữ bạn dưới ngưỡng chính là action interval của Sentry; 30 minutes là quá đủ.
  • 1500 byte nội dung thông báo. Phần dài hơn bị cắt trước khi tới thiết bị. data.event.title cộng culprit thì dư chỗ; đổ cả data.event.exception vào thì không, và dù sao trên màn hình khóa cũng không đọc nổi. Hãy để chi tiết ở sau template liên kết.

Chia sẻ với đội

Một kênh Echobell có thể được nhiều người đăng ký, và mỗi người tự chọn loại thông báo của mình. Nhờ vậy cùng một quy tắc Sentry có thể làm điện thoại người trực on-call reo lên trong khi chỉ là thông báo đẩy thường với những người khác — không tính phí theo chỗ ngồi, không cần cấu hình ca trực.

Nhưng nó không phải chính sách leo thang. Không có chuyện "nếu năm phút không ai xác nhận thì gọi người kế tiếp". Nếu cần thứ đó, bạn cần một nền tảng on-call thực thụ; Echobell lo tầng gửi đi bên dưới nó.

Những gì thiết lập này không cho bạn

Nói thẳng cho rõ:

  • Không có xác nhận (ack). Bắt máy không báo gì cho Sentry và không dừng điện thoại của những người đăng ký khác.
  • Không có ca trực hay leo thang. Hoặc tất cả người đăng ký đều nhận, hoặc không ai nhận.
  • Không khử trùng lặp ngoài phần Sentry làm. Gom nhóm và hãm tần suất diễn ra trong quy tắc Sentry; Echobell chuyển đi thứ đến nơi.
  • Không đồng bộ hai chiều. Giải quyết issue trong Sentry không xóa gì trên điện thoại bạn.

Nếu đó là những điểm không chấp nhận được thì đây không phải công cụ phù hợp. Còn nếu thứ bạn thật sự cần là "đánh thức tôi khi checkout hỏng", thì đây gần như là cách đáng tin rẻ nhất.

Khắc phục sự cố

Quy tắc kích hoạt nhưng không có gì tới. Kiểm tra Alert Rule Action đã bật trong integration chưa. Nếu tắt, integration thậm chí không xuất hiện trong danh sách hành động — và quy tắc đã lưu trước khi bạn bật sẽ giữ lại hành động cũ.

Thông báo tới nhưng trống trơn. Template của bạn đang đọc khóa ở cấp cao nhất. Sentry lồng mọi thứ dưới data.event.

Reo vì những thứ bạn không ngờ. Kiểm tra các ô Webhooks trên integration (Bẫy 1), rồi xem environment của quy tắc có còn để "All Environments" không.

Reo đi reo lại vì một lỗi. Tăng action interval của quy tắc Sentry. Cơ chế thử lại của Echobell là chuyện khác — Thử lại cuộc gọi thất bại trong cài đặt ứng dụng sẽ gọi lại cuộc gọi bạn lỡ.

Không bao giờ nhận được gì, kể cả bản thử. Hãy kích hoạt kênh bằng curl trước để loại trừ phía Echobell:

curl -X POST https://hook.echobell.one/t/<channel-token> \
  -H 'Content-Type: application/json' \
  -d '{"data":{"event":{"level":"fatal","title":"Test error","culprit":"manual test","metadata":{"type":"TestError"}}}}'

Nếu cái đó reo mà Sentry thì không, vấn đề nằm ở integration chứ không phải kênh.

Câu hỏi thường gặp

Sentry có gọi điện được không?

Không. Các hành động của issue alert trong Sentry là thông báo, tạo ticket và tích hợp với sản phẩm paging. Cuộc gọi thoại cần dịch vụ bên ngoài — hoặc một nền tảng paging như PagerDuty, hoặc một bộ nhận webhook biết đổ chuông như Echobell.

Cảnh báo Sentry có xuyên qua Không làm phiền không?

Chỉ khi nó tới dưới dạng cảnh báo kiểu cuộc gọi. Kênh Echobell loại cuộc gọi hành xử như một cuộc gọi đến, và chế độ Tập trung cùng Không làm phiền của iOS cho loại đó đi qua. Thông báo đẩy thường của bất kỳ ứng dụng nào thì không.

Dùng webhook có cần gói Sentry trả phí không?

Internal integration và hành động quy tắc cảnh báo có từ gói Developer của Sentry trở lên. Bản thân webhook không tốn thêm gì.

Vì sao biến template của tôi trống?

Gần như luôn là do đường dẫn quá ngắn. Payload cảnh báo lồng sự kiện dưới data.event, nên phải là {{data.event.title}} chứ không phải {{title}}. Kích hoạt kênh một lần rồi xem thân yêu cầu được ghi lại trong ứng dụng để biết hình dạng chính xác.

Làm sao chỉ cảnh báo cho một môi trường?

Đặt trường Environment trên quy tắc cảnh báo của Sentry. Đừng cố đọc từ data.event.tags — đó là mảng các cặp [khóa, giá trị] mà thứ tự không được bảo đảm.

Hai người có cùng nhận cuộc gọi cho một lỗi không?

Có. Chia sẻ kênh và để mỗi người đăng ký với loại thông báo họ muốn. Vì không có xác nhận, mọi người chọn "cuộc gọi" đều sẽ được gọi.

Nên lọc ở Sentry hay Echobell?

Ở Sentry khi có thể — quy tắc cũng là nơi chứa phần hãm tần suất và phạm vi môi trường. Ở Echobell khi bạn muốn hai mức khẩn cấp từ một quy tắc, khi cần khung giờ, hoặc khi hôm nay chưa sửa được quy tắc.

Tổng kết

Thiết lập gồm bốn thứ: một kênh cuộc gọi, một internal integration bật Alert Rule Action và bỏ trống các ô Webhooks, một quy tắc cảnh báo đủ hẹp để xứng đáng một cuộc gọi, và các template biết đọc data.event. Mọi thứ còn lại trong trang này là để giữ nó đủ hẹp, sao cho một tháng nữa tiếng chuông ấy vẫn còn ý nghĩa.

Tải Echobell cho iPhone hoặc lấy trên Google Play, rồi gửi lệnh curl phía trên trước khi giao bất cứ việc gì thực sự quan trọng cho đường dẫn này.

Bài liên quan