После многолетнего опыта работы с php и js, я привык иметь в ошибках стектрейс и смотреть на место, где произошла ошибка прямо из эррор-репорта. Пересев на Go пару лет назад, я был несколько удивлен, что в Go другие правила и нужно угадывать стектрейс по какой-нибудь строке типа `invalid character`. А если она произошла на проде и не известно, как ее воспроизвести, то это превращалось в целый аттракцион.
Поскольку я уверен, что ни один от этого страдал, то сделал пакет, который умеет так:
→ GitHub
Все, что он делает, это:
- Добавляет к ошибкам стектрейс.
- Отображает стектрейс и фрагменты исходников, где эта ошибка произошла (при наличии исходников, конечно).
Добавление стектрейса
Создать ошибку со стектрейсом можно одним из нескольких способов:
// создать новую
err := tracerr.New("some error")
// можно методом Errorf, который работает так же, как и fmt.Errorf
err := tracerr.Errorf("some error %d", num)
// или обернуть существующую ошибку, добавив ей стектрейс
err = tracerr.Wrap(err)
При повторном оборачивании ошибки стектрейс останется прежним и затираться не будет, это удобно в случае, если неизвестно, есть ли уже у ошибки стектрейс или нет.
Код может выглядеть как-то так:
func decodeFile(path string, data interface{}) error {
b, err := ioutil.ReadFile(path)
if err != nil {
return tracerr.Wrap(err)
}
err = json.Unmarshal(b, data)
// если err = nil, то останется nil
return tracerr.Wrap(err)
}
Отображение стектрейса
После того, как ошибка через 100500 `if err != nil { return err }` вернется на Родину в `main()` (или там, где она обрабатывается), скорее всего Вы захотите ее отобразить или залогировать.
Для это есть несколько опций, все работают, как Print (выводит текст) или Sprint (возвращает текст):
1) Отобразить текст ошибки и стектрейс:
tracerr.Print(err)
2) Отобразить текст ошибки, стектрейс и фрагмент исходников (6 строк по дефолту):
tracerr.PrintSource(err)
3) То же, но в цвете, обычно более информативно:
tracerr.PrintSourceColor(err)
4) Можно передать параметром, сколько строк кода отобразить:
tracerr.PrintSource(err, 9)
tracerr.PrintSourceColor(err, 9)
5) Или передать 2 опциональных параметра, сколько до и сколько после строки с ошибкой отобразить:
tracerr.PrintSource(err, 5, 2)
tracerr.PrintSourceColor(err, 5, 2)
Вопросы
Я уже получил некоторый фидбек, поэтому позволю себе ответить заранее на некоторые вопросы, которые уже задавали.
В: Это подходит только для дебага? Есть дебаггер.
О: Это подходит не только для дебага, можно логировать ошибки с информацией о стектрейсе, и даже с фрагментами исходников, на проде, как по моему опыту, это существенно упростит потом эти ошибки разбирать.
В: Есть супер пакет pkg/errors, почему не использовать его?
О: Есть, я сам ее вполне использовал и рад, но он не подошел мне по этим причинам:
1) Там нет простого способа отобразить стектрейс сразу с исходниками.
2) При повторном оборачивании ошибки (например, на уровень выше), стектрейс затирается менее информативным.
3) При каждом оборачивании обязательно передавать дополнительный текст ошибки, что мне кажется некоторым оверхедом при написании/чтении кода.
В: В Go ошибки это не исключения и так делать вообще нельзя.
О: Согласен, в Go ошибки это не исключения. Если Вам удобнее обрабатывать тысячи `if err != nil { return err }` каким-то другим способом — это Ваш выбор, конечно. Вы можете оборачивать только те ошибки, которые обрабатываете как исключения.
В: Стектрейс добавляет оверхед на производительность.
О: Да, добавляет, но это актуально только для мест, где ошибки создаются в огромных количествах, просто не добавляйте туда стектрейс, если это критично (уверен, что в большинстве случаев этот оверхед ничтожен).
В общем, надеюсь, этот пакет несколько облегчит Вашу гоферскую жизнь, буду рад любому фидбеку, спасибо.
Автор: zTrue