Hello everyone!

We have been investing plenty of personal time and energy for many years to share our knowledge with you all. However, we now need your help to keep this blog running. All you have to do is just click one of the adverts on the site, otherwise it will sadly be taken down due to hosting etc. costs. Thank you.

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.


ResponseWriter


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
}

AccessLoger


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

Server


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),
}
}

Test


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