File: restful-full-logging-filter.go

package info (click to toggle)
golang-github-emicklei-go-restful 3.10.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 792 kB
  • sloc: makefile: 9; sh: 6
file content (104 lines) | stat: -rw-r--r-- 2,284 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"

	restful "github.com/emicklei/go-restful/v3"
)

type User struct {
	Id   int
	Name string
}

//
// This example shows how to log both the request body and response body

func main() {
	restful.Add(newUserService())
	log.Print("start listening on localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func newUserService() *restful.WebService {
	ws := new(restful.WebService)
	ws.
		Path("/users").
		Consumes(restful.MIME_XML, restful.MIME_JSON).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	ws.Route(ws.POST("/").Filter(bodyLogFilter).To(createUser))
	return ws
}

// Route Filter (defines FilterFunction)
func bodyLogFilter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {

	inBody, err := ioutil.ReadAll(req.Request.Body)
	if err != nil {
		resp.WriteError(400, err)
		return
	}
	req.Request.Body = ioutil.NopCloser(bytes.NewReader(inBody))

	c := NewResponseCapture(resp.ResponseWriter)
	resp.ResponseWriter = c

	chain.ProcessFilter(req, resp)

	log.Println("Request body:", string(inBody))
	log.Println("Response body:", string(c.Bytes()))
}

// curl -H "content-type:application/json" http://localhost:8080/users -d '{"Id":42, "Name":"Captain Marvel"}'
//
func createUser(request *restful.Request, response *restful.Response) {
	u := new(User)
	err := request.ReadEntity(u)
	log.Print("createUser", err, u)
	response.WriteEntity(u)
}

type ResponseCapture struct {
	http.ResponseWriter
	wroteHeader bool
	status      int
	body        *bytes.Buffer
}

func NewResponseCapture(w http.ResponseWriter) *ResponseCapture {
	return &ResponseCapture{
		ResponseWriter: w,
		wroteHeader:    false,
		body:           new(bytes.Buffer),
	}
}

func (c ResponseCapture) Header() http.Header {
	return c.ResponseWriter.Header()
}

func (c ResponseCapture) Write(data []byte) (int, error) {
	if !c.wroteHeader {
		c.WriteHeader(http.StatusOK)
	}
	c.body.Write(data)
	return c.ResponseWriter.Write(data)
}

func (c *ResponseCapture) WriteHeader(statusCode int) {
	c.status = statusCode
	c.wroteHeader = true
	c.ResponseWriter.WriteHeader(statusCode)
}

func (c ResponseCapture) Bytes() []byte {
	return c.body.Bytes()
}

func (c ResponseCapture) StatusCode() int {
	return c.status
}