kyk's blog

Go Http Log

We need a logger for every routes, so made a simple http log middleware. Need to replace writer to custom one, and also take care of reading body.

package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type bodyLogWriter struct {
	http.ResponseWriter
	body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

func main() {

	httpLog := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// copy buffer from request
			var sb bytes.Buffer
			io.Copy(&sb, r.Body)

			// assign back to request body
			r.Body = ioutil.NopCloser(strings.NewReader(sb.String()))

			// create logger writer
			blw := &bodyLogWriter{
				body:           bytes.NewBufferString(""),
				ResponseWriter: w,
			}

			// call next route
			next.ServeHTTP(blw, r)

			// print out
			fmt.Printf("url: %s\nrequest params: %s \nresponse data: %s\n\n", r.URL, sb.String(), blw.body.String())
		})
	}

	// route return what body has
	route := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var sb bytes.Buffer
		io.Copy(&sb, r.Body)
		w.Header().Set("hello", "world")
		w.Write(sb.Bytes())
	})

	http.Handle("/foo", httpLog(route))

	http.ListenAndServe(":8080", nil)
}

outputs


server:
➜  httpresp go run server.go
url: /foo
request params: {"key1":"value1", "key2":"value2"}
response data: {"key1":"value1", "key2":"value2"}

client:

➜  httpresp curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:8080/foo -i
HTTP/1.1 200 OK
Hello: world
Date: Tue, 31 Dec 2019 11:19:58 GMT
Content-Length: 34
Content-Type: text/plain; charset=utf-8

{"key1":"value1", "key2":"value2"}%

References: