6 лучших практик ведения журнала Golang
16 мая 2022 г.6 лучших практик ведения журнала Golang
Давайте обсудим несколько практических правил входа в систему в Go, а также некоторые функции, о которых вы, возможно, не слышали, которые могут упростить отладку. Лучшие методы входа в систему в Go не так очевидны, и иногда нам нужно присмотреться, чтобы увидеть, что является лучшим выбором, учитывая уникальную ситуацию с обработкой ошибок в Go.
- Используйте ошибки там, где это уместно, а не строки
- Перенести ошибки
- Используйте средства форматирования, такие как fmt.Errorf()
- Форматируйте структуры там, где это уместно
- Используйте вариативные формы функций, такие как fmt.Println()
- Используйте встроенный пакет журнала
#1 - Используйте ошибки там, где это уместно, а не строки
В Go есть встроенный тип error, который позволяет разработчикам легко отличать ошибки от «обычных» строк и более явным образом проверять, чтобы функции завершались без проблем. Тип error
представляет собой interface, который просто требует, чтобы рассматриваемый тип определял функцию Error()
, которая печатает себя как строку.
```иди
тип интерфейса ошибки {
Строка с ошибкой()
Никогда не используйте обычную строку там, где уместна ошибка! Когда строка возвращается из вашей функции, вы намекаете другим разработчикам, что, когда строка не пуста, это просто «обычный бизнес». Тип error дает понять, что что-то не так, если ошибка не равна nil.
Например, давайте представим, что у нас есть функция, которая безопасно делит два числа и возвращает результат.
```иди
функция деления (a, b float64) (float64, строка) {
если б == 0 {
вернуть 0.0, "не может делить на ноль"
возврат а/б, ""
Это будет работать отлично. На самом деле, везде, где работает тип ошибки, вместо него может использоваться строка. Однако, если мы заинтересованы в написании кода, который другие разработчики смогут быстрее понять и внести в него свой вклад, мы должны использовать тип error
:
```иди
функция деления (a, b float64) (float64, ошибка) {
если б == 0 {
вернуть 0.0, errors.New("невозможно разделить на ноль")
возврат a/b, ноль
#2 - Ошибки переноса
Часто из-за лени мы просто передаем ошибки вверх по цепочке вызовов. Например, давайте посмотрим на эту функцию, которая форматирует часы и минуты в сообщение времени:
```иди
func formatTimeWithMessage (часы, минуты, целое число) (строка, ошибка) {
отформатировано, ошибка := formatTime(часы, минуты)
если ошибка != ноль {
вернуть "", ошибиться
return "Это" + отформатировано + "часы", ноль
Проблема здесь в том, что функцию formatTime можно вызывать во многих других местах нашего приложения или библиотеки. Если все, что мы делаем, это передаем необработанную ошибку, когда ошибка в конечном итоге печатается, становится очень трудно сказать, откуда именно возникла ошибка. Вместо этого давайте сделаем следующее:
```иди
func formatTimeWithMessage (часы, минуты, целое число) (строка, ошибка) {
отформатировано, ошибка := formatTime(часы, минуты)
если ошибка != ноль {
вернуть "", fmt.Errorf("formatTimeWithMessage: %v", ошибка)
return "Это" + отформатировано + "часы", ноль
Кроме того, если вы работаете в Go 1.13 или более поздней версии, вы можете изучить более явный метод Unwrap для цепочек ошибок.
#3 - Используйте средства форматирования, такие как fmt.Errorf()
[fmt.Errorf()](https://golang.org/pkg/fmt/#Errorf)
похож на fmt.Printf()
, но возвращает ошибку
вместо строки
. Возможно, вы делали это в прошлом:
```иди
err := errors.New("Произошла плохая вещь!" + oldErr.Error())
Более лаконично это можно сделать с помощью fmt.Errorf():
```иди
err := fmt.Errorf("Произошла плохая вещь! %v", oldError)
Разница в удобочитаемости становится еще более очевидной, когда рассматриваемое форматирование более сложное и включает больше переменных.
#4 - Форматирование структур там, где это необходимо
Печатные структуры могут быть довольно уродливыми и нечитаемыми. Например, следующий код:
```иди
основная функция () {
make := "Toyota"
myCar := Car{год:1996, марка: &make}
fmt.Println(моя машина)
Напечатает что-то вроде:
{1996 0x40c138}
Скорее всего, мы хотим получить значение указателя и, вероятно, хотим увидеть ключи структуры. Таким образом, мы можем реализовать метод String() по умолчанию в нашей структуре. Если мы это сделаем, то компилятор Go будет использовать этот метод при печати.
```иди
func (c Car)String() string{
return fmt.Sprintf("{make:%s, year:%d}", *c.make, c.year)
основная функция () {
make := "Toyota"
myCar := Car{год:1996, марка: &make}
fmt.Println(моя машина)
Который напечатает что-то вроде:
{марка:Toyota, год:1996}
#5 - Используйте вариативные формы функций, такие как fmt.Println()
В прошлом я часто делал следующее при регистрации:
```иди
fmt.Printf("%s победил %s в игре
", playerOne, playerTwo)
Оказывается, гораздо проще просто использовать функцию fmt.Println()
для добавления пробелов:
```иди
fmt.Println(playerOne, "победить", playerTwo, "в игре")
#6 - Используйте встроенный пакет журнала
Часто возникает искушение создать свой собственный пакет ведения журнала, но я бы посоветовал, что в большинстве случаев [стандартный пакет журнала] (https://golang.org/pkg/log/) — это вероятно все, что вам нужно. Стандартная библиотека определяет тип Logger, который вы можете использовать для индивидуальной настройки ведения журнала. Если вам не нужна такая большая власть и ответственность, вы можете сделать то, что я обычно делаю, и использовать стандартную печать и фатальную, которые просто выводят на стандартный вывод вместе с отформатированным префиксом даты и времени.
Лучшие практики
Рад, что вы зашли так далеко! Научиться правильно обрабатывать ошибки в Go — это то, что отличает продвинутых разработчиков от новичков. Стремление улучшить читабельность и удобство использования вашего кода для разработчиков сделает вас лучшим ученым-компьютерщиком и поможет вам найти больше достойных вакансий в будущем.
-Лейн Вагнер, 7 января 2020 г.
Также опубликовано [Здесь] (https://blog.boot.dev/golang/golang-logging-best-practices/)
Оригинал