Журналирование и промежуточный обработчик идентификатора запроса
Структурированное журналирование и внедрение идентификатора трассировки
«Журналирование и промежуточный обработчик идентификатора запроса» — бесплатный урок Go Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.
Зачем нужно структурированное ведение журналов?
Обычные текстовые журналы сложно анализировать при большом объёме данных. Структурированное ведение журналов (JSON или key=value) позволяет агрегаторам журналов (Datadog, Loki, ELK) фильтровать записи и сопоставлять их по полям.
Создание идентификатора запроса
Создавайте уникальный идентификатор для каждого запроса (UUID или ULID) в промежуточном ПО и добавляйте его в заголовок ответа и контекст:
func RequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-ID")
if id == "" { id = uuid.New().String() }
w.Header().Set("X-Request-ID", id)
ctx := context.WithValue(r.Context(), reqIDKey{}, id)
next.ServeHTTP(w, r.WithContext(ctx))
})
}Промежуточное ПО для ведения журналов с slog
В Go 1.21 появился log/slog для структурированного ведения журналов. Используйте его внутри промежуточного ПО:
func StructuredLogger(logger *slog.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
cw := &captureWriter{ResponseWriter: w}
next.ServeHTTP(cw, r)
logger.Info("request",
"method", r.Method,
"path", r.URL.Path,
"status", cw.status,
"latency_ms", time.Since(start).Milliseconds(),
"request_id", r.Context().Value(reqIDKey{}),
)
})
}
}captureWriter
Оборачивайте ResponseWriter, чтобы перехватывать код статуса, записанный обработчиком:
type captureWriter struct {
http.ResponseWriter
status int
}
func (cw *captureWriter) WriteHeader(code int) {
cw.status = code
cw.ResponseWriter.WriteHeader(code)
}
func (cw *captureWriter) Status() int {
if cw.status == 0 { return http.StatusOK }
return cw.status
}Добавление идентификатора запроса в каждую строку журнала
Создавайте дочерний регистратор для каждого запроса с предварительно добавленным идентификатором, а затем сохраняйте его в контексте:
reqLogger := logger.With("request_id", id)
ctx := context.WithValue(r.Context(), loggerKey{}, reqLogger)Получение регистратора из контекста
Вспомогательная функция для получения регистратора, относящегося к области действия запроса, из любого обработчика или сервиса:
func LoggerFromContext(ctx context.Context) *slog.Logger {
l, ok := ctx.Value(loggerKey{}).(*slog.Logger)
if !ok { return slog.Default() }
return l
}Уровни журналов
Используйте подходящие уровни: Debug — для подробных сообщений при разработке, Info — для сводки по запросу, Warn — для устранимых отклонений, Error — для сбоев, требующих действий. Не записывайте конфиденциальные поля (токены, пароли).
Интервалы задержки
Включайте задержку запроса в каждую строку журнала. Агрегируйте значения в интервалы гистограммы в системе метрик (Prometheus), чтобы отслеживать перцентили P50/P95/P99.
Идентификаторы корреляции в микросервисах
Передавайте заголовок X-Request-ID из входящих запросов во все исходящие вызовы HTTP и gRPC, чтобы включить распределённую трассировку без полноценной системы трассировки.
Сэмплирование журналов
Для сервисов с высоким трафиком используйте сэмплирование отладочных информационных журналов (например, записывайте один из 100 запросов на уровне отладки), чтобы снизить затраты на хранение, сохраняя все журналы ошибок.
zap и slog
zap (Uber) быстрее slog для сервисов с высокой пропускной способностью, но требует более сложной настройки. slog входит в стандартную библиотеку, переносим и достаточен для большинства сервисов. Предпочитайте slog, если только результаты тестов производительности не укажут на узкое место.
Быстрая проверка
Зачем в промежуточном программном обеспечении для журналирования нужен captureWriter?
Итоги: журналирование и идентификатор запроса
Основные положения:
- Создавайте или передавайте X-Request-ID в промежуточном программном обеспечении и сохраняйте его в контексте
- Используйте slog для структурированных журналов с полями «ключ—значение»
- captureWriter перехватывает код состояния для журналирования после обработчика
- Передавайте идентификатор корреляции во все последующие вызовы
Часто задаваемые вопросы
Урок «Журналирование и промежуточный обработчик идентификатора запроса» бесплатный?
Да — полный текст урока «Журналирование и промежуточный обработчик идентификатора запроса» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.
Чему я научусь в уроке «Журналирование и промежуточный обработчик идентификатора запроса»?
Структурированное журналирование и внедрение идентификатора трассировки Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Go Academy?
Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Журналирование и промежуточный обработчик идентификатора запроса»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Go Academy?
Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы цепочки HTTP-промежуточных обработчиков
- Журналирование и промежуточный обработчик идентификатора запроса
- Промежуточные обработчики аутентификации и ограничения частоты
- Промежуточные обработчики CORS и восстановления после паники