1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- package httpsnoop
- import (
- "io"
- "net/http"
- "time"
- )
- // Metrics holds metrics captured from CaptureMetrics.
- type Metrics struct {
- // Code is the first http response code passed to the WriteHeader func of
- // the ResponseWriter. If no such call is made, a default code of 200 is
- // assumed instead.
- Code int
- // Duration is the time it took to execute the handler.
- Duration time.Duration
- // Written is the number of bytes successfully written by the Write or
- // ReadFrom function of the ResponseWriter. ResponseWriters may also write
- // data to their underlaying connection directly (e.g. headers), but those
- // are not tracked. Therefor the number of Written bytes will usually match
- // the size of the response body.
- Written int64
- }
- // CaptureMetrics wraps the given hnd, executes it with the given w and r, and
- // returns the metrics it captured from it.
- func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Metrics {
- return CaptureMetricsFn(w, func(ww http.ResponseWriter) {
- hnd.ServeHTTP(ww, r)
- })
- }
- // CaptureMetricsFn wraps w and calls fn with the wrapped w and returns the
- // resulting metrics. This is very similar to CaptureMetrics (which is just
- // sugar on top of this func), but is a more usable interface if your
- // application doesn't use the Go http.Handler interface.
- func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics {
- m := Metrics{Code: http.StatusOK}
- m.CaptureMetrics(w, fn)
- return m
- }
- // CaptureMetrics wraps w and calls fn with the wrapped w and updates
- // Metrics m with the resulting metrics. This is similar to CaptureMetricsFn,
- // but allows one to customize starting Metrics object.
- func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) {
- var (
- start = time.Now()
- headerWritten bool
- hooks = Hooks{
- WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc {
- return func(code int) {
- next(code)
- if !headerWritten {
- m.Code = code
- headerWritten = true
- }
- }
- },
- Write: func(next WriteFunc) WriteFunc {
- return func(p []byte) (int, error) {
- n, err := next(p)
- m.Written += int64(n)
- headerWritten = true
- return n, err
- }
- },
- ReadFrom: func(next ReadFromFunc) ReadFromFunc {
- return func(src io.Reader) (int64, error) {
- n, err := next(src)
- headerWritten = true
- m.Written += n
- return n, err
- }
- },
- }
- )
- fn(Wrap(w, hooks))
- m.Duration += time.Since(start)
- }
|