Menu
CoddyTech

Обёртывание ошибок с помощью `%w`

Часть раздела Логика и управление потоком путешествия по GO на Coddy. Урок 39 из 68.

Когда в вашем приложении возникают ошибки, им часто требуется дополнительный контекст по мере прохождения через разные уровни кода. Go предоставляет для этого мощный механизм: оборачивание ошибок с помощью форматирующего глагола %w в fmt.Errorf.

Обёртывание ошибок позволяет добавить контекстную информацию к существующей ошибке, сохранив исходную ошибку в её основе. Так создаётся цепочка ошибок, которая сохраняет полную историю произошедшего:

originalErr := errors.New("file not found")
wrappedErr := fmt.Errorf("failed to load config: %w", originalErr)

Форматный глагол %w особенный: он указывает fmt.Errorf обернуть ошибку, а не просто преобразовать её в строку. Это сохраняет исходную ошибку, чтобы позже её можно было изучить с помощью таких функций, как errors.Is и errors.As.

Этот шаблон особенно полезен в крупных приложениях, где ошибка может пройти через несколько функций, каждая из которых добавляет свой контекст. Например, ошибка подключения к базе данных может быть обёрнута сообщением "failed to connect to database", а затем ещё раз сообщением "unable to start server", создавая ясную цепочку событий и показывая, где именно всё произошло.

challenge icon

Задание

Легко

Создайте систему обработки файлов, которая добавляет к ошибкам контекстную информацию по мере их прохождения через разные уровни приложения. В этом задании показано, как использовать спецификатор формата %w с fmt.Errorf, чтобы создавать цепочки ошибок, сохраняющие исходную ошибку и добавляющие значимый контекст.

Вы получите два входных значения:

  • Строку со сведениями об операции с файлом в формате "filename,operation,status" (например, "config.json,read,permission_denied")
  • Строку с контекстом системы в формате "service_name,component" (например, "UserService,ConfigLoader")

Ваша задача:

  1. Разобрать первый вход, разделив его по запятым, чтобы получить имя файла, операцию и статус
  2. Разобрать второй вход, разделив его по запятым, чтобы получить имя сервиса и компонент
  3. Создать исходную ошибку на основе статуса с помощью errors.New():
    • Если статус — "permission_denied": "permission denied"
    • Если статус — "not_found": "file not found"
    • Если статус — "corrupted": "file corrupted"
    • Для любого другого статуса: "unknown error"
  4. Создать ошибку уровня файла с обёрткой с помощью fmt.Errorf и %w: "failed to [operation] file [filename]: %w"
  5. Создать ошибку уровня компонента с обёрткой: "[component] error: %w"
  6. Создать ошибку уровня сервиса с обёрткой: "[service_name] operation failed: %w"
  7. Вывести цепочку ошибок, напечатав каждый уровень:
    • "Original error: [original_error_message]"
    • "File level: [file_level_error_message]"
    • "Component level: [component_level_error_message]"
    • "Service level: [service_level_error_message]"
  8. Вывести сводку по цепочке ошибок:
    • "Error Chain Summary:"
    • "File: [filename]"
    • "Operation: [operation]"
    • "Component: [component]"
    • "Service: [service_name]"
    • "Root cause: [original_error_message]"

Используйте пакет strings, чтобы разделить входные строки по запятым, пакет errors — чтобы создать исходную ошибку, а пакет fmt — чтобы создать ошибки с обёрткой. В этом задании показано, как обёртывание ошибок с помощью %w создаёт чёткую цепочку контекста по мере прохождения ошибок через разные уровни приложения, что значительно упрощает отладку.

Попробуйте сами

package main

import (
	"errors"
	"fmt"
	"strings"
)

func main() {
	// Считать входные данные
	var fileDetails string
	var systemContext string
	fmt.Scanln(&fileDetails)
	fmt.Scanln(&systemContext)
	
	// Разобрать входные данные
	fileInfo := strings.Split(fileDetails, ",")
	filename := fileInfo[0]
	operation := fileInfo[1]
	status := fileInfo[2]
	
	contextInfo := strings.Split(systemContext, ",")
	serviceName := contextInfo[0]
	component := contextInfo[1]
	
	// TODO: Напишите свой код ниже
	// Создать исходную ошибку на основе status
	// Создать обёрнутую ошибку на уровне файла
	// Создать обёрнутую ошибку на уровне компонента
	// Создать обёрнутую ошибку на уровне сервиса
	// Вывести ошибку на каждом уровне и сводку
	
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Логика и управление потоком

Потренируйтесь самостоятельно: Онлайн-компилятор Go