Log error response even if a handler doesn't logBody (#7867)

master
Krishnan Parthasarathi 5 years ago committed by Dee Koder
parent 36ee110563
commit 94f67ad224
  1. 65
      cmd/http-tracer.go

@ -32,6 +32,8 @@ import (
trace "github.com/minio/minio/pkg/trace" trace "github.com/minio/minio/pkg/trace"
) )
var traceBodyPlaceHolder = []byte("<BODY>")
// recordRequest - records the first recLen bytes // recordRequest - records the first recLen bytes
// of a given io.Reader // of a given io.Reader
type recordRequest struct { type recordRequest struct {
@ -56,7 +58,12 @@ func (r *recordRequest) Read(p []byte) (n int, err error) {
// Return the bytes that were recorded. // Return the bytes that were recorded.
func (r *recordRequest) Data() []byte { func (r *recordRequest) Data() []byte {
return r.buf.Bytes() // If body logging is enabled then we return the actual body
if r.logBody {
return r.buf.Bytes()
}
// ... otherwise we return <BODY> placeholder
return traceBodyPlaceHolder
} }
// recordResponseWriter - records the first recLen bytes // recordResponseWriter - records the first recLen bytes
@ -115,7 +122,13 @@ func (r *recordResponseWriter) Flush() {
// Return response body. // Return response body.
func (r *recordResponseWriter) Body() []byte { func (r *recordResponseWriter) Body() []byte {
return r.body.Bytes() // If there was an error response or body logging is enabled
// then we return the body contents
if r.statusCode >= 400 || r.logBody {
return r.body.Bytes()
}
// ... otherwise we return the <BODY> place holder
return traceBodyPlaceHolder
} }
// getOpName sanitizes the operation name for mc // getOpName sanitizes the operation name for mc
@ -136,12 +149,9 @@ func getOpName(name string) (op string) {
// Trace gets trace of http request // Trace gets trace of http request
func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Request) trace.Info { func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Request) trace.Info {
name := getOpName(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()) name := getOpName(runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name())
bodyPlaceHolder := []byte("<BODY>")
var reqBodyRecorder *recordRequest var reqBodyRecorder *recordRequest
t := trace.Info{FuncName: name} t := trace.Info{FuncName: name}
reqBodyRecorder = &recordRequest{Reader: r.Body, logBody: logBody} reqBodyRecorder = &recordRequest{Reader: r.Body, logBody: logBody}
r.Body = ioutil.NopCloser(reqBodyRecorder) r.Body = ioutil.NopCloser(reqBodyRecorder)
@ -154,40 +164,39 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
t.NodeName = host t.NodeName = host
} }
rq := trace.RequestInfo{Time: time.Now().UTC(), Method: r.Method, Path: r.URL.Path, RawQuery: r.URL.RawQuery, Client: r.RemoteAddr} // Setup a http request body recorder
rq.Headers = cloneHeader(r.Header) reqHeaders := cloneHeader(r.Header)
rq.Headers.Set("Content-Length", strconv.Itoa(int(r.ContentLength))) reqHeaders.Set("Content-Length", strconv.Itoa(int(r.ContentLength)))
rq.Headers.Set("Host", r.Host) reqHeaders.Set("Host", r.Host)
for _, enc := range r.TransferEncoding { for _, enc := range r.TransferEncoding {
rq.Headers.Add("Transfer-Encoding", enc) reqHeaders.Add("Transfer-Encoding", enc)
} }
if logBody {
// If body logging is disabled then we print <BODY> as a placeholder
// for the actual body.
rq.Body = reqBodyRecorder.Data()
} else { rq := trace.RequestInfo{
rq.Body = bodyPlaceHolder Time: time.Now().UTC(),
Method: r.Method,
Path: r.URL.Path,
RawQuery: r.URL.RawQuery,
Client: r.RemoteAddr,
Headers: reqHeaders,
Body: reqBodyRecorder.Data(),
} }
// Setup a http response body recorder // Setup a http response body recorder
respBodyRecorder := &recordResponseWriter{ResponseWriter: w, logBody: logBody} respBodyRecorder := &recordResponseWriter{ResponseWriter: w, logBody: logBody}
f(respBodyRecorder, r) f(respBodyRecorder, r)
rs := trace.ResponseInfo{Time: time.Now().UTC()} rs := trace.ResponseInfo{
rs.Headers = cloneHeader(respBodyRecorder.Header()) Time: time.Now().UTC(),
rs.StatusCode = respBodyRecorder.statusCode Headers: cloneHeader(respBodyRecorder.Header()),
StatusCode: respBodyRecorder.statusCode,
Body: respBodyRecorder.Body(),
}
if rs.StatusCode == 0 { if rs.StatusCode == 0 {
rs.StatusCode = http.StatusOK rs.StatusCode = http.StatusOK
} }
bodyContents := respBodyRecorder.Body()
if bodyContents != nil {
rs.Body = bodyContents
}
if !logBody {
// If there was no error response and body logging is disabled
// then we print <BODY> as a placeholder for the actual body.
rs.Body = bodyPlaceHolder
}
t.ReqInfo = rq t.ReqInfo = rq
t.RespInfo = rs t.RespInfo = rs
return t return t

Loading…
Cancel
Save