Label request metrics with standard HTTP methods only (closes #274) #277
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -314,6 +315,58 @@ func requestCountsByHandler(
|
|||||||
return counts
|
return counts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMetricsGivesMadeUpMethodsOneLabel checks that the metrics middleware
|
||||||
|
// gives requests with methods that are not standard ones a single method
|
||||||
|
// label, "other", and still serves each request with the method it was sent
|
||||||
|
// with. With a label per method, any client could add series to the
|
||||||
|
// registry without limit by making up a new method for each request.
|
||||||
|
func TestMetricsGivesMadeUpMethodsOneLabel(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// The line /metrics shows once both made-up methods have been served.
|
||||||
|
const want = `http_request_duration_seconds_count{` +
|
||||||
|
`code="200",handler="unmatched",method="other",service=""} 2`
|
||||||
|
|
||||||
|
registry := prometheus.NewRegistry()
|
||||||
|
mw := &Middleware{
|
||||||
|
log: slog.Default(),
|
||||||
|
config: &config.Config{},
|
||||||
|
metricsRegistry: registry,
|
||||||
|
}
|
||||||
|
|
||||||
|
var served []string
|
||||||
|
|
||||||
|
handler := mw.Metrics()(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
served = append(served, r.Method)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
|
||||||
|
methods := []string{"FROBNICATE", "WIBBLE"}
|
||||||
|
for _, method := range methods {
|
||||||
|
handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequestWithContext(
|
||||||
|
t.Context(), method, "/", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("methods the handler was served: %v", served)
|
||||||
|
|
||||||
|
if !slices.Equal(served, methods) {
|
||||||
|
t.Errorf("methods the handler was served = %v, want %v",
|
||||||
|
served, methods)
|
||||||
|
}
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
promhttp.HandlerFor(registry, promhttp.HandlerOpts{}).ServeHTTP(rec,
|
||||||
|
httptest.NewRequestWithContext(
|
||||||
|
t.Context(), http.MethodGet, "/metrics", nil))
|
||||||
|
|
||||||
|
if !strings.Contains(rec.Body.String(), want) {
|
||||||
|
t.Errorf("/metrics does not count both made-up methods as one; "+
|
||||||
|
"want the line %q in:\n%s", want, rec.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestLoggingLeavesOutSubmittedSigningKey checks that a login, a POST /
|
// TestLoggingLeavesOutSubmittedSigningKey checks that a login, a POST /
|
||||||
// whose form carries the signing key, leaves no trace of the key in the
|
// whose form carries the signing key, leaves no trace of the key in the
|
||||||
// request's log line.
|
// request's log line.
|
||||||
|
|||||||
Reference in New Issue
Block a user