Gỡ Lỗi Mã Lua Trực Tuyến - nói dối e blog

Gỡ Lỗi Mã Lua Trực Tuyến

Từ lâu, nhiều người luôn thắc mắc làm thế nào để gỡ lỗi các dịch vụ xây dựng bằng skynet.
Câu trả lời ngắn gọn của tôi là: hãy rà soát kỹ mã nguồn và thêm các thông tin ghi log. Câu trả lời dài hơn: hãy hiểu sâu về cấu trúc skynet, tận dụng triệt để các giao diện giám sát được tích hợp sẵn, tự phát triển công cụ hỗ trợ gỡ lỗi.

Trong nhiều năm qua, tôi đã từng viết không ít các công cụ gỡ lỗi Lua, nhưng xin phép không đào lại các bài viết cũ. Hôm nay tôi muốn chia sẻ về việc tích hợp bàn điều khiển gỡ lỗi vào phiên bản chính thức 1.0. Nói cụ thể hơn là khả năng theo dõi từng bước (single-step) từng coroutine Lua riêng lẻ. Tính năng này giống như chiếc nạng hỗ trợ việc học đi cho người mới bắt đầu, dù có những người sẽ phụ thuộc vào nó suốt đời.

Ban đầu tôi dự định triển khai hai chế độ khác nhau:

  1. Chế độ đóng băng toàn bộ dịch vụ để gỡ lỗi từ từ
  2. Chế độ không làm gián đoạn khả năng xử lý tin nhắn khác, chỉ theo dõi từng luồng xử lý tin nhắn đơn lẻ

Ưu điểm của chế độ đóng băng:
Khi gỡ lỗi, toàn bộ máy ảo Lua của dịch vụ sẽ bị treo, giúp trạng thái nội bộ không thay đổi trong suốt quá trình kiểm tra.

Nhược điểm của chế độ đóng băng:
Nếu áp dụng trên môi trường sản phẩm, đặc biệt với các dịch vụ trọng yếu, hệ thống sẽ nhanh chóng bị quá tải do khả năng xử lý tin nhắn giảm sút nghiêm trọng (trong môi trường lượng yêu cầu cao, việc treo máy chỉ vài giây cũng có thể gây thảm họa).

Tôi đã quyết định loại bỏ chế độ đóng băng. Vì trong giai đoạn phát triển, hệ thống thường chỉ xử lý vài tin nhắn đồng thời, và bạn chỉ tập trung gỡ lỗi phần code đang viết. Những thay đổi trạng thái nhỏ có thể dễ dàng theo dõi thông qua các thông báo log chi tiết. Hơn nữa, chế độ không làm gián đoạn dịch vụ mang lại trải nghiệm dễ chịu hơn nhiều.

Tuy nhiên, phần cơ sở hạ tầng ở cấp C vẫn được thiết kế để hỗ trợ cả hai chế độ. Trường hợp cần chế độ đóng băng trong tương lai, việc tích hợp sẽ rất đơn giản.

Cơ chế底层

Cốt lõi là xây dựng một kênh truyền thông riêng biệt không đi qua hàng đợi tin nhắn skynet. Điều này giúp vượt qua cơ chế truyền thông giữa các dịch vụ của skynet để trực tiếp gỡ lỗi dịch vụ.

Để có thể theo dõi từng bước, chúng ta cần sửa đổi nhẹ hook debug có sẵn của Lua. Cụ thể là cho phép yield ra khỏi hook - tính năng vốn được hỗ trợ bởi API C của Lua nhưng lại bị ẩn đi ở phiên bản API Lua.

Có một “cạm bẫy” đáng chú ý: Có thể do một lỗi trong cách triển khai Lua, tôi sẽ đề cập kỹ hơn ở phần cuối.

Với hạ tầng đã sẵn sàng, chúng ta có thể xây dựng tiện ích gỡ lỗi bằng Lua một cách thoải mái.

Giao diện người dùng

Điểm khởi đầu là debug_console. Mỗi lần cần gỡ lỗi một dịch vụ Lua, ta khởi động một dịch vụ gỡ lỗi riêng biệt sử dụng kênh truyền thông đã nói ở trên. Dịch vụ bị theo dõi sẽ cài đặt một hook kiểm tra trước khi xử lý mỗi tin nhắn. Khi phát hiện đang bị gỡ lỗi, nó sẽ trích xuất lệnh từ người dùng để thực thi.

Vì các dịch vụ skynet ở trạng thái treo khi không có tin nhắn xử lý, ta cần gắn bộ hẹn giờ định kỳ để kiểm tra kênh gỡ lỗi (vì tin nhắn gỡ lỗi không đi qua cơ chế lập lịch của skynet). Hiện tại tôi thiết lập 100 lần kiểm tra mỗi giây, có thể bật/tắt động bằng lệnh gỡ lỗi.

Tính năng “watch” theo dõi tin nhắn

Do bản chất dựa trên tin nhắn của skynet, tôi thêm lệnh watch - cho phép theo dõi một loại tin nhắn cụ thể, đi kèm hàm điều kiện để quyết định khi nào dừng (breakpoint).

Kết hợp với module tiêm mã đã viết trước đó, khi xử lý tin nhắn bị tạm dừng, chúng ta có thể quan sát và thay đổi môi trường hiện hành.

Triển khai thực tế

Trên nhánh lua53 của skynet, mã nguồn đã được commit. Các bạn quan tâm có thể trải nghiệm. Hiện tại chỉ mới tích hợp các tính năng cơ bản, các tính năng nâng cao sẽ được bổ sung dần.

Hướng dẫn sử dụng

  1. Khởi động dịch vụ debug_console (mặc định đã bật trong file config mẫu)
  2. Sử dụng telnet kết nối đến cổng gỡ lỗi (thường là 127.0.0.1:8000)
  3. Dùng lệnh debug address để kết nối (attach) với dịch vụ cần theo dõi (ví dụ: debug :0100000c)
  4. Khi không theo dõi tin nhắn nào, dấu nhắc sẽ hiển thị địa chỉ dịch vụ
  5. Nhập cont để thoát khỏi chế độ gỡ lỗi

Trong môi trường gỡ lỗi:

  • Bạn có thể nhập các biểu thức hoặc lệnh Lua hợp lệ
  • Dùng watch(proto, cond) để thiết lập điểm dừng
    • proto: tên giao thức (thường là "lua")
    • cond: hàm điều kiện (tuỳ chọn) nhận tham số tin nhắn, trả về true khi cần dừng

Các lệnh đặc biệt:

  • `
0%