-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
137 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# go-check-err-chains | ||
|
||
Линтер проверяет что текст ошибок содержит префикс указывающий на пакет/функцию/метод в котором произошла ошибка. | ||
|
||
Проверка проводится только для экспортируемых функций. | ||
|
||
Пример: | ||
```go | ||
package pkg | ||
|
||
func Get(key string) error { | ||
id, err := strconv.Atoi(key) | ||
if err != nil { | ||
return errors.New("pkg.Get: %w; key=%s", err, key) // good | ||
} | ||
if empty { | ||
return sql.ErrNoRows // bad | ||
} | ||
return nil | ||
} | ||
``` | ||
|
||
|
||
## Зачем | ||
|
||
Этот линтер – попытка навести порядок влогах. | ||
|
||
По логам часто не понятно где произошла проблема. | ||
|
||
У этой проблемы уже есть есть пара решений, но все имеют существенные недостатки: | ||
|
||
1. Использовать логер снабжающий записи указанием на файл и строку где лог был написан. | ||
|
||
Файл и номер строки логер указать может, но это будет место где вызвали log.Error, | ||
а не место в котором произошла ошибка. | ||
|
||
Это значит что ошибки нужно логировать прямо там где они произошли. | ||
В итоге логи начинают писать повсюду и с большой избыточностью. | ||
|
||
Одна ошибка генерирует несколько похожих сообщений про одну и ту же ошибку | ||
и в каждом сообщении немного свой контекст и чтобы увидеть полный контекст | ||
необходимо собрать все эти записи. | ||
|
||
2. Использовать для ошибок сторонние библиотеки типа [pkg/errors](https://github.com/pkg/errors) | ||
|
||
Есть множество библиотек которые сохраянют стек вызовов при создания ошибки. | ||
|
||
Это не плохой подход, но есть ряд минусов: | ||
- повсюду нужно использовать одну определенную библиотеку для ошибок | ||
- плохо сочетается с нативным [врапингом через %w](https://go.dev/blog/go1.13-errors) | ||
|
||
|
||
На данный момент оптимальным компромисом кажется идти идиоматическим путем принятым | ||
в стандартной библиотеке: | ||
|
||
Примеры ошибок из стандартной библиотеки: | ||
- strconv.Atoi: parsing "x": invalid syntax | ||
- plugin.Open("file.so"): realpath failed | ||
- bytes.Buffer: too large | ||
- open file.go: no such file or directory | ||
- strings.Builder.Grow: negative count | ||
|
||
Видно что строгой схемы нет, но паттерн прослеживается: вначале имя пакета/метода/функции, затем двоеточие и далее подробности. | ||
|
||
```go | ||
package pkg | ||
|
||
func Get(key string) error { | ||
id, err := strconv.Atoi(key) | ||
if err != nil { | ||
return errors.New("pkg.Get: %w; key=%s", err, key) | ||
} | ||
// ... | ||
} | ||
``` | ||
|
||
`pkg.Get("abc")` дает ошибку: | ||
``` | ||
pkg.Get: strconv.Atoi: parsing "abc": invalid syntax; key=abc | ||
``` | ||
|
||
У такого подхода ряд плюсов: | ||
|
||
- Хорошо стыкуется с ошибками стандартной библиотеки | ||
|
||
- Дружит с врапингом | ||
|
||
- Писать текст ошибки проще: | ||
|
||
`failed to get package cause key abc is not valid ...` vs `pkg.Get: strconv.Atoi: parsing "abc": invalid syntax`. | ||
|
||
Второй вариант инженеру проще и читать и писать. | ||
|
||
- Логи удобно грепать | ||
|
||
|
||
А главный минус подхода в том что нужно следить за согласованностью имени пакета/функции | ||
и текста ошибок/логов, ведь при переименовании функции нужно не забыть поменять | ||
все ошибки/логи. | ||
|
||
Именнно эту проблему и решает этот линтер. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters