Commit f7a24d3
Antonio Mika
·
2026-10-25 21:57:09 -0400 EDT
parent 8d599bd
feat(metrics): let servers outside net/http record user metrics
2 files changed,
+29,
-5
| ... | ... | @@ -88,14 +88,20 @@ func (m *UserMetrics) Handler(next http.Handler) http.Handler { | |
| 88 | 88 | next.ServeHTTP(mw, r.WithContext(context.WithValue(r.Context(), ctxUserKey{}, &user))) | |
| 89 | 89 | ||
| 90 | 90 | status := mw.Status() | |
| 91 | - | user = m.resolveUser(r, user, status) | |
| 92 | - | labels := []string{user, strconv.Itoa(status), metricMethod(r.Method)} | |
| 93 | - | m.requests.WithLabelValues(labels...).Inc() | |
| 94 | - | m.duration.WithLabelValues(labels...).Observe(time.Since(start).Seconds()) | |
| 95 | - | m.bytes.WithLabelValues(user).Add(float64(mw.bytes)) | |
| 91 | + | m.Observe(m.resolveUser(r, user, status), status, r.Method, time.Since(start), mw.bytes) | |
| 96 | 92 | }) | |
| 97 | 93 | } | |
| 98 | 94 | ||
| 95 | + | // Observe records one request for servers that can't use Handler, such as | |
| 96 | + | // tuns's gin logger. user must already be confirmed to exist. A negative | |
| 97 | + | // size, which gin reports when nothing was written, counts as zero bytes. | |
| 98 | + | func (m *UserMetrics) Observe(user string, status int, method string, elapsed time.Duration, bytes int64) { | |
| 99 | + | labels := []string{user, strconv.Itoa(status), metricMethod(method)} | |
| 100 | + | m.requests.WithLabelValues(labels...).Inc() | |
| 101 | + | m.duration.WithLabelValues(labels...).Observe(elapsed.Seconds()) | |
| 102 | + | m.bytes.WithLabelValues(user).Add(float64(max(bytes, 0))) | |
| 103 | + | } | |
| 104 | + | ||
| 99 | 105 | func (m *UserMetrics) resolveUser(r *http.Request, user string, status int) string { | |
| 100 | 106 | if user != "" { | |
| 101 | 107 | m.known.Add(user, struct{}{}) |
| ... | ... | @@ -129,6 +129,24 @@ func TestUserMetricsMethod(t *testing.T) { | |
| 129 | 129 | } | |
| 130 | 130 | } | |
| 131 | 131 | ||
| 132 | + | func TestUserMetricsObserve(t *testing.T) { | |
| 133 | + | reg := prometheus.NewRegistry() | |
| 134 | + | m := NewUserMetrics("test", reg, UserMetricsOpts{}) | |
| 135 | + | ||
| 136 | + | m.Observe("carol", http.StatusOK, http.MethodGet, 0, 7) | |
| 137 | + | m.Observe("carol", http.StatusNotModified, "MADEUP", 0, -1) | |
| 138 | + | ||
| 139 | + | if got := metricValue(t, reg, "pico_http_requests_total", map[string]string{"user": "carol", "status": "200", "method": "GET"}); got != 1 { | |
| 140 | + | t.Errorf("200 requests = %v, want 1", got) | |
| 141 | + | } | |
| 142 | + | if got := metricValue(t, reg, "pico_http_requests_total", map[string]string{"user": "carol", "status": "304", "method": "OTHER"}); got != 1 { | |
| 143 | + | t.Errorf("304 requests = %v, want 1", got) | |
| 144 | + | } | |
| 145 | + | if got := metricValue(t, reg, "pico_http_response_bytes_total", map[string]string{"user": "carol"}); got != 7 { | |
| 146 | + | t.Errorf("bytes = %v, want 7", got) | |
| 147 | + | } | |
| 148 | + | } | |
| 149 | + | ||
| 132 | 150 | func TestUserMetricsHijack(t *testing.T) { | |
| 133 | 151 | reg := prometheus.NewRegistry() | |
| 134 | 152 | h := NewUserMetrics("test", reg, UserMetricsOpts{}).Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |