Skip to content

Commit

Permalink
feat(helpers,middlwares): enrich custom response writer with bytes wr…
Browse files Browse the repository at this point in the history
…itten field and log this field into reach request stats log
  • Loading branch information
jeamon committed Nov 9, 2023
1 parent 2f55c3f commit ae2cbc9
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
9 changes: 5 additions & 4 deletions api.middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ func (api *APIHandler) DurationMiddleware(next httprouter.Handle) httprouter.Han
next(nw, r, ps)
logger.Info(
"stats",
zap.Int("request.status", nw.statusCode),
zap.Int("request.status", nw.Status()),
zap.Int("bytes.sent", nw.Bytes()),
zap.Duration("request.duration", api.clock.Now().Sub(start)),
)
api.stats.mu.Lock()
if num, found := api.stats.status[nw.statusCode]; !found {
api.stats.status[nw.statusCode] = 1
if num, found := api.stats.status[nw.code]; !found {
api.stats.status[nw.code] = 1
} else {
api.stats.status[nw.statusCode] = num + 1
api.stats.status[nw.code] = num + 1
}
api.stats.mu.Unlock()
}
Expand Down
49 changes: 36 additions & 13 deletions helpers.response.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,62 @@ import (
"net/http"
)

// CustomResponseWriter is a wrapper for http.ResponseWriter.
// It is used to record response attributes like statusCode.
// CustomResponseWriter is a wrapper for http.ResponseWriter. It is
// used to record response details like status code and body size.
type CustomResponseWriter struct {
http.ResponseWriter
statusCode int
code int
bytes int
wrote bool
}

// NewCustomResponseWriter provides CustomResponseWriter with 200 as status code.
func NewCustomResponseWriter(rw http.ResponseWriter) *CustomResponseWriter {
return &CustomResponseWriter{
ResponseWriter: rw,
statusCode: 200,
code: 200,
}
}

// Header implements http.Header interface.
func (rw *CustomResponseWriter) Header() http.Header {
return rw.ResponseWriter.Header()
func (cw *CustomResponseWriter) Header() http.Header {
return cw.ResponseWriter.Header()
}

// WriteHeader implements http.WriteHeader interface.
func (rw *CustomResponseWriter) WriteHeader(statusCode int) {
rw.ResponseWriter.WriteHeader(statusCode)
rw.statusCode = statusCode
func (cw *CustomResponseWriter) WriteHeader(code int) {
if !cw.wrote {
cw.code = code
cw.wrote = true
cw.ResponseWriter.WriteHeader(code)
}
}

// Write implements http.Write interface.
func (rw *CustomResponseWriter) Write(bytes []byte) (int, error) {
return rw.ResponseWriter.Write(bytes)
func (cw *CustomResponseWriter) Write(bytes []byte) (int, error) {
if !cw.wrote {
cw.WriteHeader(cw.code)
}

n, err := cw.ResponseWriter.Write(bytes)
cw.bytes += n
return n, err
}

// Status returns the written status code.
func (cw *CustomResponseWriter) Status() int {
return cw.code
}

// Bytes returns bytes written as response body.
func (cw *CustomResponseWriter) Bytes() int {
return cw.bytes
}

func (rw *CustomResponseWriter) Status() int {
return rw.statusCode
// Unwrap returns native response writer and used by
// the http.ResponseController during its operation.
func (cw *CustomResponseWriter) Unwrap() http.ResponseWriter {
return cw.ResponseWriter
}

// APIError is the data model sent when an error occurred during request processing.
Expand Down

0 comments on commit ae2cbc9

Please sign in to comment.