Bọc lỗi bằng `%w`
Thuộc phần Logic và luồng điều khiển trong hành trình GO của Coddy. Bài học 39 trên 68.
Khi ứng dụng gặp lỗi, bạn thường cần bổ sung ngữ cảnh khi lỗi đi qua các lớp khác nhau trong code. Go cung cấp một cơ chế mạnh mẽ để làm việc này: bọc lỗi bằng động từ định dạng %w với fmt.Errorf.
Việc bọc lỗi cho phép bạn thêm thông tin ngữ cảnh vào một lỗi hiện có mà vẫn giữ nguyên lỗi gốc bên dưới. Nhờ đó, ta tạo được một chuỗi lỗi lưu lại đầy đủ lịch sử về những gì đã xảy ra:
originalErr := errors.New("file not found")
wrappedErr := fmt.Errorf("failed to load config: %w", originalErr)Động từ %w có chức năng đặc biệt: nó yêu cầu fmt.Errorf bọc lỗi thay vì chỉ chuyển lỗi thành chuỗi. Nhờ vậy, lỗi gốc được giữ lại để bạn có thể kiểm tra sau bằng các hàm như errors.Is và errors.As.
Mẫu này đặc biệt hữu ích trong các ứng dụng lớn, nơi một lỗi có thể đi qua nhiều hàm, mỗi hàm bổ sung thêm ngữ cảnh riêng. Ví dụ, lỗi kết nối cơ sở dữ liệu có thể được bọc thêm thông tin "failed to connect to database", rồi tiếp tục được bọc với thông tin "unable to start server", tạo thành một dấu vết rõ ràng về sự việc đã xảy ra và vị trí xảy ra.
Thử thách
DễXây dựng một hệ thống xử lý tệp, trong đó lỗi được bọc kèm thông tin ngữ cảnh khi truyền qua các lớp khác nhau của ứng dụng. Thử thách này hướng dẫn cách dùng động từ định dạng %w với fmt.Errorf để tạo chuỗi lỗi, giữ lại lỗi gốc và bổ sung ngữ cảnh có ý nghĩa.
Bạn sẽ nhận hai đầu vào:
- Một chuỗi chứa thông tin chi tiết về thao tác với tệp theo định dạng
"filename,operation,status"(ví dụ:"config.json,read,permission_denied") - Một chuỗi chứa ngữ cảnh hệ thống theo định dạng
"service_name,component"(ví dụ:"UserService,ConfigLoader")
Nhiệm vụ của bạn là:
- Phân tích đầu vào thứ nhất bằng cách tách chuỗi theo dấu phẩy để lấy tên tệp, thao tác và trạng thái
- Phân tích đầu vào thứ hai bằng cách tách chuỗi theo dấu phẩy để lấy tên dịch vụ và thành phần
- Tạo lỗi gốc dựa trên trạng thái bằng
errors.New():- Nếu trạng thái là
"permission_denied":"permission denied" - Nếu trạng thái là
"not_found":"file not found" - Nếu trạng thái là
"corrupted":"file corrupted" - Với mọi trạng thái khác:
"unknown error"
- Nếu trạng thái là
- Tạo lỗi được bọc ở cấp tệp bằng
fmt.Errorfvới%w:"failed to [operation] file [filename]: %w" - Tạo lỗi được bọc ở cấp thành phần:
"[component] error: %w" - Tạo lỗi được bọc ở cấp dịch vụ:
"[service_name] operation failed: %w" - Hiển thị chuỗi lỗi bằng cách in ra từng cấp:
"Original error: [original_error_message]""File level: [file_level_error_message]""Component level: [component_level_error_message]""Service level: [service_level_error_message]"
- Hiển thị bản tóm tắt chuỗi lỗi:
"Error Chain Summary:""File: [filename]""Operation: [operation]""Component: [component]""Service: [service_name]""Root cause: [original_error_message]"
Dùng gói strings để tách các chuỗi đầu vào theo dấu phẩy, gói errors để tạo lỗi gốc và gói fmt để tạo lỗi được bọc. Thử thách này hướng dẫn cách bọc lỗi bằng %w tạo ra dấu vết ngữ cảnh rõ ràng khi lỗi đi qua các lớp khác nhau của ứng dụng, giúp việc gỡ lỗi hiệu quả hơn nhiều.
Tự làm thử
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// Đọc đầu vào
var fileDetails string
var systemContext string
fmt.Scanln(&fileDetails)
fmt.Scanln(&systemContext)
// Phân tích các đầu vào
fileInfo := strings.Split(fileDetails, ",")
filename := fileInfo[0]
operation := fileInfo[1]
status := fileInfo[2]
contextInfo := strings.Split(systemContext, ",")
serviceName := contextInfo[0]
component := contextInfo[1]
// TODO: Viết code bên dưới
// Tạo lỗi gốc dựa trên status
// Tạo lỗi được bọc ở cấp tệp
// Tạo lỗi được bọc ở cấp thành phần
// Tạo lỗi được bọc ở cấp dịch vụ
// In ra từng cấp lỗi và phần tóm tắt
}Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Logic và luồng điều khiển
1Luồng điều khiển nâng cao
Switch với `fallthrough`Thoát khỏi vòng lặp lồng nhauTiếp tục một vòng lặp cụ thểCâu lệnh `goto`Ôn tập: điều khiển vòng lặp nâng cao4Dự án: Danh sách việc cần làm đơn giản
Thiết lập dự ánThêm một việc cần làm7Xử lý lỗi chuyên sâu
Kiểu lỗi tùy chỉnhBọc lỗi bằng `%w`Gỡ bọc lỗi bằng `errors.Is`Gỡ bọc lỗi bằng `errors.As`Tìm hiểu `panic`Sử dụng `recover`Ôn tập: phép chia an toàn2Struct và phương thức
Định nghĩa phương thức cho structReceiver giá trịReceiver con trỏChọn receiverPhương thức và hàmÔn tập: hành vi của struct5Tìm hiểu chuyên sâu về map
Map chứa structCon trỏ làm giá trị của mapKiểm tra map nilSo sánh các mapÔn tập: bộ đếm tần suất từ8Dự án: Quản lý hàng tồn kho đơn giản
Tổng quan dự ánKiểm tra hàng tồn kho3Interface (cơ bản)
Interface là gì?Định nghĩa interfaceTriển khai interfaceDùng kiểu interfaceInterface rỗngKhẳng định kiểuType switchÔn tập: hình dạng và hành viTự luyện tập: Trình biên dịch Go online