-
Notifications
You must be signed in to change notification settings - Fork 14
/
requestlogger.go
100 lines (82 loc) · 2.46 KB
/
requestlogger.go
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
package internal
import (
"bytes"
"context"
"io"
"net/http"
"github.com/go-chi/chi/middleware"
"github.com/anz-bank/sysl-go/config"
"github.com/anz-bank/sysl-go/log"
)
type RequestLogger interface {
LogResponse(response *http.Response) // Calls Flush() automatically
ResponseWriter(http.ResponseWriter) http.ResponseWriter
FlushLog() // Must be called if using the ResponseWriter() func
}
type httpData struct {
body bytes.Buffer
header http.Header
}
type requestLogger struct {
ctx context.Context
req httpData
resp httpData
protoMajor int
rw http.ResponseWriter
flushed bool
}
func (r *requestLogger) LogResponse(resp *http.Response) {
if resp != nil {
b, _ := io.ReadAll(resp.Body)
resp.Body.Close()
resp.Body = io.NopCloser(bytes.NewBuffer(b))
r.resp.body.Write(b)
r.resp.header = resp.Header
}
r.FlushLog()
}
func (r *requestLogger) ResponseWriter(base http.ResponseWriter) http.ResponseWriter {
rw := middleware.NewWrapResponseWriter(base, r.protoMajor)
rw.Tee(&r.resp.body)
r.rw = rw
return rw
}
func (r *requestLogger) FlushLog() {
ctx := r.ctx
if r.flushed {
log.Info(ctx, "Already flushed the request")
return
}
r.flushed = true
if r.rw != nil {
r.resp.header = r.rw.Header()
}
ctx = log.WithStr(ctx, "logger", "common/internal/requestlogger.go")
ctx = log.WithStr(ctx, "func", "FlushLog()")
reqBody := r.req.body.String()
log.Debugf(ctx, "Request: header - %s\nbody[len:%v]: - %s", r.req.header, len(reqBody), reqBody)
respBody := r.resp.body.String()
log.Debugf(ctx, "Response: header - %s\nbody[len:%v]: - %s", r.resp.header, len(respBody), respBody)
}
type nopLogger struct{}
func (r *nopLogger) LogResponse(_ *http.Response) {}
func (r *nopLogger) ResponseWriter(base http.ResponseWriter) http.ResponseWriter { return base }
func (r *nopLogger) FlushLog() {}
func NewRequestLogger(ctx context.Context, req *http.Request) (RequestLogger, context.Context) {
cfg := config.GetDefaultConfig(ctx)
if cfg != nil && cfg.Library.Log.LogPayload {
l := &requestLogger{
ctx: InitFieldsFromRequest(ctx, req),
protoMajor: req.ProtoMajor,
}
l.req.header = req.Header.Clone()
if req.Body != nil && req.Method != http.MethodGet {
b, _ := io.ReadAll(req.Body)
_ = req.Body.Close()
req.Body = io.NopCloser(bytes.NewBuffer(b))
l.req.body.Write(b)
}
return l, l.ctx
}
return &nopLogger{}, ctx
}