I'm trying to log some data on my web server, so I created a loggingMiddleware
that serves the next request and then logs the data, I thought this way I would have all the necessary data inside the r *http.Request
pointer
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// call next handler
next.ServeHTTP(o, r)
// get requestID
reqID := middleware.GetReqID(r.Context())
log.WithFields(
log.Fields{
"request_id": reqID, // drops requestID
"method": r.Method, // http method
"remote_address": r.RemoteAddr, // remote address
"url": r.URL.String(), // url used by the client to access the service
"referer": r.Referer(), // Referer header if present
"user_agent": r.UserAgent(), // User-Agent header
"content_length": r.ContentLength, // Content-Length header if present"
},
).Info()
})
However for the RequestID this is true only if the RequestID
middleware is mounted before the loggingMiddleware
Non-Working
...
// get a new chi rotuter
router = chi.NewRouter()
// MIDDLEWARES
// log
// use logrus to log requests
router.Use(LoggingMiddleware)
// requestID
// Generate a unique id for every request
// ids are grouped based on client hostname
router.Use(middleware.RequestID)
...
Working
...
// get a new chi rotuter
router = chi.NewRouter()
// MIDDLEWARES
// requestID
// Generate a unique id for every request
// ids are grouped based on client hostname
router.Use(middleware.RequestID)
// log
// use logrus to log requests
router.Use(LoggingMiddleware)
...
Is this the expected behavior? Should the r *http.Request
pointer point to the "updated" version of the request? Is there a way to get around this?
Because if I want, for example, extract a username from a JWT token and put it in the r.Context()
so I can log it later, this would require a separate middleware to be mounted before the loggingMiddleware
.
Sorry for my english, please ask if there's something not clear.
Thanks
middleware.RequestID
adds the request ID to the request context by usinghttp.Request.WithContext
:Per the documentation:
Therefore, because it "returns a shallow copy of r", and it is (a pointer to) this shallow copy which it passes to
next.ServeHTTP
, ifmiddleware.RequestID
is mounted second, then ther
inLoggingMiddleware
is pointing to a different*http.Request
than the one which contains the modified context, and so its context will not contain the request ID. If, on the other hand,middleware.RequestID
is mounted first, thenLoggingMiddleware
will receive a pointer to the shallow copy thatr.WithContext
returned, and everything will work as expected.