Реализовать логирование.
-
Поддержать возможность структурного логирования в
JSON
формате (по умолчанию) и текстовом. Пользователь должен иметь возможность выбрать желаемый формат с помощью переменной окружения:export JSON_LOG=1
-
Предоставить пользователю возможность задавать уровни логирования (
info
(по умолчанию),error
,debug
и пр.). Пользователь должен иметь возможность задать уровень логирования с помощью переменной окружения:export LOG_LEVEL=error
-
Реализовать
middleware
для логирования всех входящих запросов и результатов их выполнения (HTTP
код, текст ошибки). -
Реализовать перехват и восстановление (recover) после паники на уровне
HTTP API
с учетом ситуаций, когда восстановление невозможно. Сервис должен логировать информацию по перехваченной панике.
- Для реализации логирования применить
slog
из стандартной библиотекиGolang
.
Паника в языке Go
во многом похожа на исключения в других языках
программирования. Однако ее не следует использовать как быстрый способ передать
ошибку на более высокий уровень. Паники обычно указывает на критическую ошибку,
которая делает продолжением работы сервиса невозможным (чем-то похоже на функцию
assert
из С++).
В каких случаях имеет смысл паниковать? Рассмотрим несколько допустимых сценариев (этот список не полный, но позволяет продемонстрировать идею):
-
Мисконфигурация по вине пользователя: Сервис читает конфигурацию на старте и обнаруживает, что она содержит недопустимые значения.
-
Грубая ошибка разработчика: Возникла ситуация, которая явно указывает на ошибку в коде, например:
func Wrap(extra string, err error) error { if err == nil { panic("wrapping nil error") } return fmt.Errorf("%s: %w", extra, err) }
-
Непредвиденная ошибка во время подготовки окружения для юнит- или интеграционных тестов:
func (s *SmokeTestSuite) SetupTest() { conn, err := grpc.NewClient(s.GRPCAddress, grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { panic(err) } s.Conn = conn }
-
Паника в коде сторонних библиотек: В некоторых случаях паника может возникнуть из-за ошибок в сторонних библиотеках.
Для повышения стабильности работы сервиса разработчики часто реализуют
специальную middleware
функцию, который перехватывает панику при обработке
запросов и пытается вернуть программу в работоспособное состояние, записывая
ошибку в лог. Именно такую функцию и необходимо реализовать в задании.
К сожалению в ряде случаев восстановление после паники невозможно, один из таких сценариев проиллюстрирован в коде ниже:
package main
import "fmt"
func doWork(i int) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from", r)
}
}()
if i == 2 {
panic("Kaboom!")
}
fmt.Println("Doing something useful with", i)
}
func unrecoverablePanic() {
var f func()
go f()
}
func main() {
for range 3 {
doWork(1)
doWork(2)
doWork(3)
}
// Raise unrecoverable panic.
unrecoverablePanic()
// Will never get here.
doWork(1)
}
-
SLog - очень краткий обзор использования
slog
от командыGolang
. -
Структурированное логирование в Go с помощью Slog - подробное руководство по использованию
slog
. -
Panic and Recover in Go - подробно про панику в
Go
и способы восстановления после нее.