Как вернуть объект регистратора из объекта запроса после его обслуживания обработчиком?

Я пытаюсь научиться использовать промежуточное ПО в Go. Мне удалось отправить объект регистратора с контекстом запроса в функции обработчика. Но как только запрос обработан и объект регистратора заполнен данными/ошибками из функций обработчика, я хочу иметь доступ к измененному объекту. Но согласно моей текущей реализации я получаю нулевой объект.

logger := log.WithFields(log.Fields{
                ReqIdKey: reqId,
                "proto":  r.Proto,
                "method": r.Method,
                "uri":    r.URL.RequestURI(),
                "startTime": time.Now(),
                "body":      t,
                "header":      r.Header,
                "remote-addr": r.RemoteAddr,
            })
            ctx = context.WithValue(ctx, "logger", logger)
//Update as per suggestions recieved.
            r = r.WithContext(ctx)

            m := httpsnoop.CaptureMetrics(next, w, r)
            
//Post this point the internal functions modify the log and add errors etc extra fields which I want to access
//For example:
//logger := logcontext.GetLogCtx(ctx) 
//logger = logger.WithFields(log.Fields{"error": err})

            logger = logger.WithFields(log.Fields{
                "responseTime": m.Duration,
                "status":       m.Code,
            })
            return logger.Info("Request Completed")

Получен ответ:

{"body":null,"header":{"Accept":["*/*"],"Accept-Encoding":["gzip, deflate, br"],"Connection":["keep-alive"],"Postman-Token":["a1ef5d6c-94cb-4b64-b350-700c37eff6b4"],"User-Agent":["PostmanRuntime/7.26.2"]},"level":"info","method":"GET","msg":"Request completed","proto":"HTTP/1.1","remote-addr":"127.0.0.1:36254","responseTime":2463797,"startTime":"2020-07-28T00:31:22.97954465+05:30","status":503,"time":"2020-07-28T00:31:22+05:30","uri":"/api/v1/getSomething/some/xyz/abc/2","x-request-id":"f493a4ad-035c-48a8-9207-64a922c96961"}

Ожидание добавленного поля ошибки от функции-обработчика.

Я знаю, что в этом случае есть некоторая концептуальная ошибка, но не могу ее понять.

Итак, в основном я хочу регистрировать все один раз, а не несколько раз, для этого нужно получить окончательные поля и все только в промежуточном программном обеспечении.


person gaurav1999    schedule 27.07.2020    source источник
comment
У вас уже есть ссылка на регистратор в вашей локальной переменной logger, просто используйте ее вместо того, чтобы возвращать ее из контекста.   -  person Adrian    schedule 27.07.2020
comment
да, я использовал его, но там не видны поля ошибок, которые добавляются обработчиками. В идеале он должен быть там, потому что обработчики изменили тот же объект и добавили дополнительное поле через logger.WithError(err)   -  person gaurav1999    schedule 27.07.2020
comment
После преобразования типа вы не должны использовать log_p, если ok имеет значение false, хотя неясно, почему вы вообще вызываете Value. Просто используйте регистратор напрямую (значение не может возвращать что-либо еще).   -  person Peter    schedule 27.07.2020
comment
@ gaurav1999 gaurav1999, когда вы добавляете поля с помощью WithFields, возвращаемый регистратор представляет собой оболочку оригинала. Эти поля не добавляются в исходный регистратор, а добавляются только в новый регистратор.   -  person Burak Serdar    schedule 27.07.2020
comment
Не уверен, что это так, потому что поля, которые я ранее добавил, все еще регистрируются, например заголовок, URL-адрес и т. д.   -  person gaurav1999    schedule 27.07.2020
comment
Глядя на источник, они заботятся о старых значениях и добавляют новые поля.   -  person gaurav1999    schedule 27.07.2020


Ответы (1)


Если цель состоит в том, чтобы получить доступ к модифицированному регистратору, вы можете просто использовать экземпляр регистратора, созданный вами в этом промежуточном программном обеспечении, вместо того, чтобы получать его обратно из ответа. Однако это причина, по которой ваш код не работает:

m := httpsnoop.CaptureMetrics(next, w, r.WithContext(ctx))

WithContext возвращает новый запрос с новым контекстом. Старый запрос не изменился. Сделайте это вместо этого:

r=r.WithContext(ctx)
m := httpsnoop.CaptureMetrics(next, w, r)

Это назначит новый запрос, содержащий новый контекст, r. Используйте новый r для доступа к измененному запросу и контексту.

person Burak Serdar    schedule 27.07.2020
comment
Эти две части кода делают одно и то же. Исходная строка передает возвращенный запрос от r.WithContext в качестве параметра запроса к CaptureMetrics; ваше изменение просто сохраняет его в локальной переменной, чтобы сделать то же самое. - person Adrian; 27.07.2020
comment
@Adrian, это влияет на остальную часть следующего кода. В исходном посте измененный запрос потерян. - person Burak Serdar; 27.07.2020
comment
Это справедливо, но на самом деле не объяснено в ответе. Хотя более простое решение — просто использовать ссылку, которую они уже получили, вместо того, чтобы выдергивать ее из контекста без причины. - person Adrian; 27.07.2020
comment
@ Адриан, добавил это к ответу. - person Burak Serdar; 27.07.2020
comment
Я сделал: - r = r.WithContext(ctx) m:= httpsnoop.CaptureMetrics(next, w, r) logger = logger.WithFields(log.Fields{responseTime: m.Duration,status: m.Code,}) Итак речь идет об использовании той же ссылки, но я все еще не могу увидеть объект ошибки в конечном объекте регистратора. - person gaurav1999; 27.07.2020