Доступ к контексту, где нет http.Request - PullRequest
0 голосов
/ 19 сентября 2019

Я устанавливаю X-Request-Id в context в промежуточном программном обеспечении (, как показано ниже ), чтобы я мог использовать его там, где есть *http.Request struct - например, req.Context().Value(middleware.ReqIdKey).Однако в моей кодовой базе есть места, где у меня нет возможности получить доступ к *http.Request struct, поэтому я не могу использовать context для получения X-Request-Id.Есть ли способ в Go или я пытаюсь сделать что-то в корне неправильно?

internal / middleware / requesttid.go

Это промежуточное ПО, где я установил X-Request-Id в context.В настоящее время он называется http.ListenAndServe(":8080", middleware.RequestId(SomeHandler)) в моем "серверном" пакете.

package middleware

import (
    "context"
    "github.com/google/uuid"
    "net/http"
)

type val string
const ReqIdKey val = "X-Request-Id"

func RequestId(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        val := req.Header.Get("X-Request-Id")
        if val == "" {
            val = uuid.New().String()
        }

        ctx1 := context.WithValue(req.Context(), ReqIdKey, val)
        ctx2 := req.WithContext(ctx1)

        handler.ServeHTTP(res, ctx2)
    })
}

internal / logger / logger.go

Это еще один пакет, к которому мне нужно получить доступcontext или просто X-Request-Id значение.Кстати, вызов logger.Config происходит до запуска сервера.

package logger

import (
    "github.com/sirupsen/logrus"
    "os"
)

var Log *logrus.Entry

func Config() {
    logrus.SetLevel(logrus.InfoLevel)
    logrus.SetOutput(os.Stdout)
    logrus.SetFormatter(&logrus.JSONFormatter{})

    Log = logrus.WithFields(logrus.Fields{
        "request_id": ..., // I need X-Request-Id value to go here so that all logs have it
    })
}

Ответы [ 2 ]

4 голосов
/ 19 сентября 2019

Если у вас есть http.Request, вы можете получить доступ к его контексту и значениям.Если у вас нет запроса, но вам нужен контекст: получите контекст и передайте его в ваше calltree в качестве явного параметра (условно это первый параметр).

(В Go нет магии и ничегоне передается в функцию, прямо или косвенно просто не существует.)

2 голосов
/ 19 сентября 2019

Во-первых, вы должны передавать свой контекст везде, где это необходимо.Если вам это нужно в функции Config(), передайте ее туда:

func Config(ctx context.Context) {
  /* ... * /
}

Но вы, вероятно, вызываете Config() один раз, при запуске, а не по запросу, что приводит ко второму пункту:

Вы не должны передавать контекст или данные в области запроса в целом в функцию конфигурации.Это полностью задом наперед.

Скорее, вы должны передать свой регистратор в ваш обработчик / промежуточное ПО и позволить ему регистрироваться с данными запроса:

func handleSomePath(logger *logrus.Entry) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        /* do something */
        logger.WithFields(logrus.Fields{
            "request_id": /* ... */
        })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...