0Pricing
Go Academy · Урок

Журналирование и промежуточный обработчик идентификатора запроса

Структурированное журналирование и внедрение идентификатора трассировки

«Журналирование и промежуточный обработчик идентификатора запроса» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Основы цепочки HTTP-промежуточных обработчиков
  2. Журналирование и промежуточный обработчик идентификатора запроса
  3. Промежуточные обработчики аутентификации и ограничения частоты
  4. Промежуточные обработчики CORS и восстановления после паники
← Назад к Go Academy