How to get the logger object back from request object once it's served by handler?

414 Views Asked by At

I am trying to learn how to use Middleware in Go. I am successful in sending the logger object with the request context to the handler functions. But once the request is processed and the logger object is filled with the data/errors from handler functions, I want to be able to access the modified object. But as per my current implementation I am getting a nil object.

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")

Response Recieved:

{"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"}

Expecting the added "error" field from the handler function.

I am aware that there is some conceptual mistake in this case, but not able to get it.

So basically I want to log everything once, not multiple times, for that need to get the final fields and everything at middleware only.

1

There are 1 best solutions below

5
Burak Serdar On

If the purpose is to access the modified logger, then you can simply use the logger instance you created in that middleware instead of getting it back from the response. However, this is the reason why your code is not working:

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

WithContext returns a new request with the new context. The old request is unmodified. Do this instead:

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

This will assign the new request containing the new context to r. Use the new r going forward to access the modified request and the context.