Cleanup ResponseWriter function for audit and trace (#8283)

This commit is contained in:
poornas
2019-09-23 13:34:28 -07:00
committed by kannappanr
parent 3b05e175d7
commit 2e02e1889b
3 changed files with 84 additions and 104 deletions

View File

@@ -18,7 +18,6 @@ package cmd
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net"
@@ -34,8 +33,6 @@ import (
trace "github.com/minio/minio/pkg/trace"
)
var traceBodyPlaceHolder = []byte("<BODY>")
// recordRequest - records the first recLen bytes
// of a given io.Reader
type recordRequest struct {
@@ -78,81 +75,7 @@ func (r *recordRequest) Data() []byte {
return r.buf.Bytes()
}
// ... otherwise we return <BODY> placeholder
return traceBodyPlaceHolder
}
// recordResponseWriter - records the first recLen bytes
// of a given http.ResponseWriter
type recordResponseWriter struct {
// Data source to record
http.ResponseWriter
// Response body should be logged
logBody bool
// Internal recording buffer
headers bytes.Buffer
body bytes.Buffer
// The status code of the current HTTP request
statusCode int
// Indicate if headers are written in the log
headersLogged bool
// number of bytes written
bytesWritten int
}
// Write the headers into the given buffer
func (r *recordResponseWriter) writeHeaders(w io.Writer, statusCode int, headers http.Header) {
n, _ := fmt.Fprintf(w, "%d %s\n", statusCode, http.StatusText(statusCode))
r.bytesWritten += n
for k, v := range headers {
n, _ := fmt.Fprintf(w, "%s: %s\n", k, v[0])
r.bytesWritten += n
}
}
// Record the headers.
func (r *recordResponseWriter) WriteHeader(i int) {
r.statusCode = i
if !r.headersLogged {
r.writeHeaders(&r.headers, i, r.ResponseWriter.Header())
r.headersLogged = true
}
r.ResponseWriter.WriteHeader(i)
}
func (r *recordResponseWriter) Write(p []byte) (n int, err error) {
n, err = r.ResponseWriter.Write(p)
r.bytesWritten += n
if !r.headersLogged {
// We assume the response code to be '200 OK' when WriteHeader() is not called,
// that way following Golang HTTP response behavior.
r.writeHeaders(&r.headers, http.StatusOK, r.ResponseWriter.Header())
r.headersLogged = true
}
if r.statusCode >= http.StatusBadRequest || r.logBody {
// Always logging error responses.
r.body.Write(p)
}
return n, err
}
func (r *recordResponseWriter) Size() int {
return r.bytesWritten
}
// Calls the underlying Flush.
func (r *recordResponseWriter) Flush() {
r.ResponseWriter.(http.Flusher).Flush()
}
// Return response body.
func (r *recordResponseWriter) Body() []byte {
// If there was an error response or body logging is enabled
// then we return the body contents
if r.statusCode >= http.StatusBadRequest || r.logBody {
return r.body.Bytes()
}
// ... otherwise we return the <BODY> place holder
return traceBodyPlaceHolder
return logger.BodyPlaceHolder
}
// getOpName sanitizes the operation name for mc
@@ -205,16 +128,15 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
Headers: reqHeaders,
Body: reqBodyRecorder.Data(),
}
// Setup a http response body recorder
respBodyRecorder := &recordResponseWriter{ResponseWriter: w, logBody: logBody}
f(logger.NewResponseWriter(respBodyRecorder), r)
rw, _ := w.(*logger.ResponseWriter)
rw.LogBody = logBody
f(rw, r)
rs := trace.ResponseInfo{
Time: time.Now().UTC(),
Headers: respBodyRecorder.Header().Clone(),
StatusCode: respBodyRecorder.statusCode,
Body: respBodyRecorder.Body(),
Headers: rw.Header().Clone(),
StatusCode: rw.StatusCode,
Body: rw.Body(),
}
if rs.StatusCode == 0 {
@@ -225,9 +147,10 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
t.RespInfo = rs
t.CallStats = trace.CallStats{
Latency: rs.Time.Sub(rq.Time),
InputBytes: reqBodyRecorder.Size(),
OutputBytes: respBodyRecorder.Size(),
Latency: rs.Time.Sub(rw.StartTime),
InputBytes: reqBodyRecorder.Size(),
OutputBytes: rw.Size(),
TimeToFirstByte: rw.TimeToFirstByte,
}
return t
}