27/01/2021 - GO
This example will help you to capture response status code and body size then log it. You can log request related data as well if you wish but it is outside of this post's scope.
package response
import (
"bufio"
"fmt"
"net"
"net/http"
)
// Acts as an adapter for `http.ResponseWriter` type to store response status
// code and size.
type ResponseWriter struct {
http.ResponseWriter
code int
size int
}
// Returns a new `ResponseWriter` type by decorating `http.ResponseWriter` type.
func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
return &ResponseWriter{
ResponseWriter: w,
}
}
// Overrides `http.ResponseWriter` type.
func (r *ResponseWriter) WriteHeader(code int) {
if r.Code() == 0 {
r.code = code
r.ResponseWriter.WriteHeader(code)
}
}
// Overrides `http.ResponseWriter` type.
func (r *ResponseWriter) Write(body []byte) (int, error) {
if r.Code() == 0 {
r.WriteHeader(http.StatusOK)
}
var err error
r.size, err = r.ResponseWriter.Write(body)
return r.size, err
}
// Overrides `http.Flusher` type.
func (r *ResponseWriter) Flush() {
if fl, ok := r.ResponseWriter.(http.Flusher); ok {
if r.Code() == 0 {
r.WriteHeader(http.StatusOK)
}
fl.Flush()
}
}
// Overrides `http.Hijacker` type.
func (r *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj, ok := r.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("the hijacker interface is not supported")
}
return hj.Hijack()
}
// Returns response status code.
func (r *ResponseWriter) Code() int {
return r.code
}
// Returns response size.
func (r *ResponseWriter) Size() int {
return r.size
}
package middleware
import (
"log"
"net/http"
"response"
)
// AccessLoger helps logging request and response related data.
func AccessLoger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rw := response.NewResponseWriter(w)
h.ServeHTTP(rw, r)
log.Println("status:", rw.Code(), "size:", rw.Size(), "bytes")
})
}
package http
import (
"net/http"
)
// NewServer returns `http.Server` pointer type.
func NewServer(address string, handler http.Handler) *http.Server {
return &http.Server{
Addr: address,
Handler: AccessLoger(handler),
}
}
If you send an example request to one of your endpoints, the log should look like below.
2021/01/27 17:19:39 status: 200 size: 63 bytes