Линтер проверяет что текст ошибок содержит префикс указывающий на пакет/функцию/метод в котором произошла ошибка.
Проверка проводится только для экспортируемых функций.
Пример:
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
}
Этот линтер – попытка навести порядок влогах.
По логам часто не понятно где произошла проблема.
У этой проблемы уже есть есть пара решений, но все имеют существенные недостатки:
-
Использовать логер снабжающий записи указанием на файл и строку где лог был написан.
Файл и номер строки логер указать может, но это будет место где вызвали log.Error, а не место в котором произошла ошибка.
Это значит что ошибки нужно логировать прямо там где они произошли. В итоге логи начинают писать повсюду и с большой избыточностью.
Одна ошибка генерирует несколько похожих сообщений про одну и ту же ошибку и в каждом сообщении немного свой контекст и чтобы увидеть полный контекст необходимо собрать все эти записи.
-
Использовать для ошибок сторонние библиотеки типа pkg/errors
Есть множество библиотек которые сохраянют стек вызовов при создания ошибки.
Это не плохой подход, но есть ряд минусов:
- повсюду нужно использовать одну определенную библиотеку для ошибок
- плохо сочетается с нативным врапингом через %w
На данный момент оптимальным компромисом кажется идти идиоматическим путем принятым в стандартной библиотеке:
Примеры ошибок из стандартной библиотеки:
- 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
Видно что строгой схемы нет, но паттерн прослеживается: вначале имя пакета/метода/функции, затем двоеточие и далее подробности.
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 ...
vspkg.Get: strconv.Atoi: parsing "abc": invalid syntax
.Второй вариант инженеру проще и читать и писать.
-
Логи удобно грепать
А главный минус подхода в том что нужно следить за согласованностью имени пакета/функции и текста ошибок/логов, ведь при переименовании функции нужно не забыть поменять все ошибки/логи.
Именнно эту проблему и решает этот линтер.