about summary refs log tree commit diff
path: root/vendor/github.com/felixge/httpsnoop/capture_metrics.go
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-08-16 19:50:26 +0200
committerEmile <git@emile.space>2024-08-16 19:50:26 +0200
commit1a57267a17c2fc17fb6e104846fabc3e363c326c (patch)
tree1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /vendor/github.com/felixge/httpsnoop/capture_metrics.go
initial commit
Diffstat (limited to 'vendor/github.com/felixge/httpsnoop/capture_metrics.go')
-rw-r--r--vendor/github.com/felixge/httpsnoop/capture_metrics.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/vendor/github.com/felixge/httpsnoop/capture_metrics.go b/vendor/github.com/felixge/httpsnoop/capture_metrics.go
new file mode 100644
index 0000000..b77cc7c
--- /dev/null
+++ b/vendor/github.com/felixge/httpsnoop/capture_metrics.go
@@ -0,0 +1,86 @@
+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)
+}