Skip to content

Commit c5fc6de

Browse files
authored
fix: report correct request paths from workspace proxy metrics (#21302)
I noticed while looking at scale test metrics that we don't always report a useful path in the API request metrics. ![image.png](https://app.graphite.com/user-attachments/assets/a5b0dadf-9c2f-46a8-a6c1-3ad5f6201edb.png) There are a lot of requests with path `/*`. I chased this problem to the workspace proxy, where we mount a the proxy router as a child of a "root" router to support some high level endpoints like `latency-check`. Because we query the path from the Chi route context in the prometheus middleware _before_ the request is actually handled, we can have a partially resolved pattern match only corresponding to the root router. The fix is to always re-resolve the path, rather than accept a partially resolved path.
1 parent 9f34a1d commit c5fc6de

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

coderd/httpmw/prometheus.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ func getRoutePattern(r *http.Request) string {
106106
return ""
107107
}
108108

109-
if pattern := rctx.RoutePattern(); pattern != "" {
110-
// Pattern is already available
111-
return pattern
112-
}
113-
114109
routePath := r.URL.Path
115110
if r.URL.RawPath != "" {
116111
routePath = r.URL.RawPath

coderd/httpmw/prometheus_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package httpmw_test
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"net/http/httptest"
78
"testing"
89

910
"github.com/go-chi/chi/v5"
11+
"github.com/google/uuid"
1012
"github.com/prometheus/client_golang/prometheus"
1113
cm "github.com/prometheus/client_model/go"
1214
"github.com/stretchr/testify/assert"
@@ -164,6 +166,42 @@ func TestPrometheus(t *testing.T) {
164166
require.Equal(t, "UNKNOWN", reqProcessed["path"])
165167
require.Equal(t, "GET", reqProcessed["method"])
166168
})
169+
170+
t.Run("Subrouter", func(t *testing.T) {
171+
t.Parallel()
172+
reg := prometheus.NewRegistry()
173+
promMW := httpmw.Prometheus(reg)
174+
175+
r := chi.NewRouter()
176+
r.Use(promMW)
177+
r.Get("/api/v2/workspaceagents/{workspaceagent}/pty", func(w http.ResponseWriter, r *http.Request) {})
178+
179+
// Mount under a root router like wsproxy does.
180+
rootRouter := chi.NewRouter()
181+
rootRouter.Get("/latency-check", func(w http.ResponseWriter, r *http.Request) {})
182+
rootRouter.Mount("/", r)
183+
184+
agentID := uuid.UUID{1}
185+
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v2/workspaceagents/%s/pty", agentID.String()), nil)
186+
187+
sw := &tracing.StatusWriter{ResponseWriter: httptest.NewRecorder()}
188+
rootRouter.ServeHTTP(sw, req)
189+
190+
metrics, err := reg.Gather()
191+
require.NoError(t, err)
192+
require.Greater(t, len(metrics), 0)
193+
metricLabels := getMetricLabels(metrics)
194+
195+
reqProcessed, ok := metricLabels["coderd_api_requests_processed_total"]
196+
require.True(t, ok, "coderd_api_requests_processed_total metric not found")
197+
require.Equal(t, "/api/v2/workspaceagents/{workspaceagent}/pty", reqProcessed["path"])
198+
require.Equal(t, "GET", reqProcessed["method"])
199+
200+
concurrentRequests, ok := metricLabels["coderd_api_concurrent_requests"]
201+
require.True(t, ok, "coderd_api_concurrent_requests metric not found")
202+
require.Equal(t, "/api/v2/workspaceagents/{workspaceagent}/pty", concurrentRequests["path"])
203+
require.Equal(t, "GET", concurrentRequests["method"])
204+
})
167205
}
168206

169207
func getMetricLabels(metrics []*cm.MetricFamily) map[string]map[string]string {

0 commit comments

Comments
 (0)