mirror of
https://github.com/minio/minio.git
synced 2024-12-25 06:35:56 -05:00
audit: Merge ResponseWriter with RecordAPIStats (#9496)
ResponseWriter & RecordAPIStats has similar role, merge them. This commit will also fix wrong auditing for STS and Web and others since they are using ResponseWriter instead of the RecordAPIStats.
This commit is contained in:
parent
c7470e6e6e
commit
27632ca6ec
@ -36,8 +36,6 @@ import (
|
|||||||
"github.com/minio/minio/pkg/bucket/object/tagging"
|
"github.com/minio/minio/pkg/bucket/object/tagging"
|
||||||
"github.com/minio/minio/pkg/handlers"
|
"github.com/minio/minio/pkg/handlers"
|
||||||
"github.com/minio/minio/pkg/madmin"
|
"github.com/minio/minio/pkg/madmin"
|
||||||
|
|
||||||
stats "github.com/minio/minio/cmd/http/stats"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -366,7 +364,7 @@ func collectAPIStats(api string, f http.HandlerFunc) http.HandlerFunc {
|
|||||||
globalHTTPStats.currentS3Requests.Inc(api)
|
globalHTTPStats.currentS3Requests.Inc(api)
|
||||||
defer globalHTTPStats.currentS3Requests.Dec(api)
|
defer globalHTTPStats.currentS3Requests.Dec(api)
|
||||||
|
|
||||||
statsWriter := stats.NewRecordAPIStats(w)
|
statsWriter := logger.NewResponseWriter(w)
|
||||||
|
|
||||||
f.ServeHTTP(statsWriter, r)
|
f.ServeHTTP(statsWriter, r)
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
stats "github.com/minio/minio/cmd/http/stats"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
)
|
)
|
||||||
@ -167,13 +167,13 @@ func (st *HTTPStats) toServerHTTPStats() ServerHTTPStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics from http request and response data
|
// Update statistics from http request and response data
|
||||||
func (st *HTTPStats) updateStats(api string, r *http.Request, w *stats.RecordAPIStats, durationSecs float64) {
|
func (st *HTTPStats) updateStats(api string, r *http.Request, w *logger.ResponseWriter, durationSecs float64) {
|
||||||
// A successful request has a 2xx response code
|
// A successful request has a 2xx response code
|
||||||
successReq := (w.RespStatusCode >= 200 && w.RespStatusCode < 300)
|
successReq := (w.StatusCode >= 200 && w.StatusCode < 300)
|
||||||
|
|
||||||
if !strings.HasSuffix(r.URL.Path, prometheusMetricsPath) {
|
if !strings.HasSuffix(r.URL.Path, prometheusMetricsPath) {
|
||||||
st.totalS3Requests.Inc(api)
|
st.totalS3Requests.Inc(api)
|
||||||
if !successReq && w.RespStatusCode != 0 {
|
if !successReq && w.StatusCode != 0 {
|
||||||
st.totalS3Errors.Inc(api)
|
st.totalS3Errors.Inc(api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,8 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
rw := logger.NewResponseWriter(w)
|
rw := logger.NewResponseWriter(w)
|
||||||
rw.LogBody = logBody
|
rw.LogErrBody = true
|
||||||
|
rw.LogAllBody = logBody
|
||||||
f(rw, r)
|
f(rw, r)
|
||||||
|
|
||||||
rq := trace.RequestInfo{
|
rq := trace.RequestInfo{
|
||||||
|
@ -19,7 +19,6 @@ package stats
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IncomingTrafficMeter counts the incoming bytes from the underlying request.Body.
|
// IncomingTrafficMeter counts the incoming bytes from the underlying request.Body.
|
||||||
@ -63,45 +62,3 @@ func (w *OutgoingTrafficMeter) Flush() {
|
|||||||
func (w OutgoingTrafficMeter) BytesCount() int {
|
func (w OutgoingTrafficMeter) BytesCount() int {
|
||||||
return w.countBytes
|
return w.countBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordAPIStats is a response writer which stores
|
|
||||||
// information of the underlying http response.
|
|
||||||
type RecordAPIStats struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
TTFB time.Duration // TimeToFirstByte.
|
|
||||||
StartTime time.Time
|
|
||||||
RespStatusCode int
|
|
||||||
|
|
||||||
firstByteRead bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRecordAPIStats creates a new response writer with
|
|
||||||
// start time set to the function call time.
|
|
||||||
func NewRecordAPIStats(w http.ResponseWriter) *RecordAPIStats {
|
|
||||||
return &RecordAPIStats{
|
|
||||||
ResponseWriter: w,
|
|
||||||
StartTime: time.Now().UTC(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteHeader calls the underlying WriteHeader
|
|
||||||
// and records the response status code.
|
|
||||||
func (r *RecordAPIStats) WriteHeader(i int) {
|
|
||||||
r.RespStatusCode = i
|
|
||||||
r.ResponseWriter.WriteHeader(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write calls the underlying Write and updates TTFB and other info
|
|
||||||
func (r *RecordAPIStats) Write(p []byte) (n int, err error) {
|
|
||||||
if !r.firstByteRead {
|
|
||||||
r.TTFB = time.Now().UTC().Sub(r.StartTime)
|
|
||||||
r.firstByteRead = true
|
|
||||||
}
|
|
||||||
n, err = r.ResponseWriter.Write(p)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush calls the underlying Flush.
|
|
||||||
func (r *RecordAPIStats) Flush() {
|
|
||||||
r.ResponseWriter.(http.Flusher).Flush()
|
|
||||||
}
|
|
||||||
|
@ -26,16 +26,17 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/minio/minio/cmd/logger/message/audit"
|
"github.com/minio/minio/cmd/logger/message/audit"
|
||||||
|
|
||||||
stats "github.com/minio/minio/cmd/http/stats"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResponseWriter - is a wrapper to trap the http response status code.
|
// ResponseWriter - is a wrapper to trap the http response status code.
|
||||||
type ResponseWriter struct {
|
type ResponseWriter struct {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
StatusCode int
|
StatusCode int
|
||||||
// Response body should be logged
|
// Log body of 4xx or 5xx responses
|
||||||
LogBody bool
|
LogErrBody bool
|
||||||
|
// Log body of all responses
|
||||||
|
LogAllBody bool
|
||||||
|
|
||||||
TimeToFirstByte time.Duration
|
TimeToFirstByte time.Duration
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
// number of bytes written
|
// number of bytes written
|
||||||
@ -69,7 +70,7 @@ func (lrw *ResponseWriter) Write(p []byte) (int, error) {
|
|||||||
lrw.writeHeaders(&lrw.headers, http.StatusOK, lrw.Header())
|
lrw.writeHeaders(&lrw.headers, http.StatusOK, lrw.Header())
|
||||||
lrw.headersLogged = true
|
lrw.headersLogged = true
|
||||||
}
|
}
|
||||||
if lrw.StatusCode >= http.StatusBadRequest || lrw.LogBody {
|
if (lrw.LogErrBody && lrw.StatusCode >= http.StatusBadRequest) || lrw.LogAllBody {
|
||||||
// Always logging error responses.
|
// Always logging error responses.
|
||||||
lrw.body.Write(p)
|
lrw.body.Write(p)
|
||||||
}
|
}
|
||||||
@ -96,7 +97,7 @@ var BodyPlaceHolder = []byte("<BODY>")
|
|||||||
func (lrw *ResponseWriter) Body() []byte {
|
func (lrw *ResponseWriter) Body() []byte {
|
||||||
// If there was an error response or body logging is enabled
|
// If there was an error response or body logging is enabled
|
||||||
// then we return the body contents
|
// then we return the body contents
|
||||||
if lrw.StatusCode >= http.StatusBadRequest || lrw.LogBody {
|
if (lrw.LogErrBody && lrw.StatusCode >= http.StatusBadRequest) || lrw.LogAllBody {
|
||||||
return lrw.body.Bytes()
|
return lrw.body.Bytes()
|
||||||
}
|
}
|
||||||
// ... otherwise we return the <BODY> place holder
|
// ... otherwise we return the <BODY> place holder
|
||||||
@ -145,11 +146,11 @@ func AuditLog(w http.ResponseWriter, r *http.Request, api string, reqClaims map[
|
|||||||
timeToFirstByte time.Duration
|
timeToFirstByte time.Duration
|
||||||
)
|
)
|
||||||
|
|
||||||
st, ok := w.(*stats.RecordAPIStats)
|
st, ok := w.(*ResponseWriter)
|
||||||
if ok {
|
if ok {
|
||||||
statusCode = st.RespStatusCode
|
statusCode = st.StatusCode
|
||||||
timeToResponse = time.Now().UTC().Sub(st.StartTime)
|
timeToResponse = time.Now().UTC().Sub(st.StartTime)
|
||||||
timeToFirstByte = st.TTFB
|
timeToFirstByte = st.TimeToFirstByte
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
Loading…
Reference in New Issue
Block a user