-
Notifications
You must be signed in to change notification settings - Fork 0
/
request.go
154 lines (125 loc) · 4.09 KB
/
request.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package log
import (
"bufio"
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"regexp"
"strings"
"time"
"github.com/cygy/ginamite/common/request"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)
const (
obfuscatorReplacingString = "***"
// ErrorContextKey field name of the error in the context, if provided this error will be logged.
ErrorContextKey = "request_error"
// RequestIDHeaderName header name of the request ID value.
RequestIDHeaderName = "X-Request-ID"
)
type requestLogWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (w requestLogWriter) Write(b []byte) (int, error) {
w.body.Write(b)
return w.ResponseWriter.Write(b)
}
// InjectRequestLogger log the requests and the responses.
func InjectRequestLogger(logResponseBody bool) gin.HandlerFunc {
// Here are the obfuscators.
sensitiveObfuscatorRegExp := regexp.MustCompile(`"(password)":"([^\"]*)"`)
sensitiveObfuscatorReplacingString := []byte(fmt.Sprintf(`"$1":"%s"`, obfuscatorReplacingString))
emailObfuscatorRegExp := regexp.MustCompile(`([^\/\"]*)@`)
emailObfuscatorReplacingString := []byte(fmt.Sprintf(`%s@`, obfuscatorReplacingString))
// Return the middleware.
return func(c *gin.Context) {
// Get the request details
if len(c.Request.Header.Get(RequestIDHeaderName)) == 0 {
c.Request.Header.Set(RequestIDHeaderName, uuid.NewString())
}
requestIP := request.GetRealIPAddress(c)
requestMethod := c.Request.Method
requestPath := c.Request.URL.Path
requestQuery := c.Request.URL.RawQuery
if len(requestQuery) > 0 {
requestPath = requestPath + "?" + requestQuery
}
requestBody := ""
if strings.HasPrefix(c.Request.Header.Get("Content-Type"), "multipart/form-data") {
requestBody = "not logged"
} else if c.Request.Body != nil {
if body, _ := ioutil.ReadAll(c.Request.Body); body != nil {
obfuscatedBody := sensitiveObfuscatorRegExp.ReplaceAll(body, sensitiveObfuscatorReplacingString)
obfuscatedBody = emailObfuscatorRegExp.ReplaceAll(obfuscatedBody, emailObfuscatorReplacingString)
requestBody = string(obfuscatedBody[:])
// Restore the io.ReadCloser to its original state
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
}
requestHeaders := map[string]string{}
for key, value := range c.Request.Header {
requestHeaders[key] = value[0]
}
// Replace the writer
var writer *requestLogWriter
if logResponseBody {
writer = &requestLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = writer
}
// Start timer
start := time.Now()
// Process request
c.Next()
// Stop timer
end := time.Now()
latency := end.Sub(start)
entry := WithFields(logrus.Fields{
"IP": requestIP,
"latency": latency,
"request": logrus.Fields{
"method": requestMethod,
"URI": requestPath,
"headers": requestHeaders,
"body": requestBody,
},
})
// Get the error if provided
if err, errExists := c.Get(ErrorContextKey); errExists {
entry = entry.WithFields(logrus.Fields{
"error": err.(string),
})
}
// Get the response details
responseLog := logrus.Fields{
"code": c.Writer.Status(),
}
if logResponseBody {
obfuscatedResponseBody := writer.body.Bytes()
// Check the first two bytes to know if a bytes array is gzipped or not.
bufferReader := bufio.NewReader(bytes.NewReader(obfuscatedResponseBody))
if testBytes, err := bufferReader.Peek(2); err == nil && testBytes[0] == 31 && testBytes[1] == 139 {
gzipReader, err := gzip.NewReader(bytes.NewBuffer(obfuscatedResponseBody))
if err == nil {
var data []byte
if data, err = ioutil.ReadAll(gzipReader); err == nil {
obfuscatedResponseBody = data
}
}
gzipReader.Close()
if err != nil {
obfuscatedResponseBody = []byte{}
responseLog["error"] = "can not uncompress body"
}
}
obfuscatedResponseBody = emailObfuscatorRegExp.ReplaceAll(obfuscatedResponseBody, emailObfuscatorReplacingString)
responseLog["body"] = string(obfuscatedResponseBody[:])
}
entry.WithFields(logrus.Fields{
"response": responseLog,
}).Info("request")
}
}