I was wondering if there is a way to log the responses when using ListenAndServe.
As far as I can tell, the handler doesn't have access to a "Response" object. Just a ResponseWriter, so I cannot call httputil.DumpResponse.
http.ResponseWriter is an interface. You can use embedding to extend it for logging as follows.
package main
import (
"log"
"net/http"
)
func sampleHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
response := []byte("Sample Response")
w.Write(response)
}
type loggingResponseWriter struct {
status int
body string
http.ResponseWriter
}
func (w *loggingResponseWriter) WriteHeader(code int) {
w.status = code
w.ResponseWriter.WriteHeader(code)
}
func (w *loggingResponseWriter) Write(body []byte) (int, error) {
w.body = string(body)
return w.ResponseWriter.Write(body)
}
func responseLogger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
loggingRW := &loggingResponseWriter{
ResponseWriter: w,
}
h.ServeHTTP(loggingRW, r)
log.Println("Status : ", loggingRW.status, "Response : ", loggingRW.body)
})
}
func main() {
http.Handle("/", responseLogger(http.HandlerFunc(sampleHandler)))
http.ListenAndServe(":8080", nil)
}
You can wrap the handler functions that you want to log responses for with responseLogger.
You can't because the response technically doesn't exist until you write it to the ResponseWriter
.
But in the response
is just the header
, body
and response code
so in the handler function you can use method Header()
on the ResponseWriter
to get the header and then you can log the response code
and the body
before you write it to the ResponseWriter
.
If you provide an example of what you are trying to do, I can elaborate on how to do it.
This is what I did to fix this for a small project: I use this in all my handlers:
type transaction struct {
res Response // Create this type also
req Request // Create this type also
}
func NewTransaction(w http.ResponseWriter, req *http.Request) *transaction{}
Log := make(chan transaction, 100)
go func{
// Read from channel and log the info however you want.
}()
func indexHandler(w http.ResponseWriter, req *http.Request) {
tx := NewTransaction(w, req) // Struct with the request and response
defer func() {
Log <- tx
}()
/*
Handle request here
*/
// Update request and response
Request.Body = body
}
And at the end of the handler function, after having served the requested data, I update the values for the request and the response.
And have a goroutine listening to the channel Log and doing all your logging.
Also you can write a wrapper function that serves the file and returns the response.
As an alternative, one can use fasthttp.