-
Notifications
You must be signed in to change notification settings - Fork 360
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: improve configurability of prometheus metrics (#450)
Closes #446 This patch introduces a new boolean configuration parameter `collapse_request_paths` in the prometheus configuration stanza of the `oathkeeper.yml` file: ``` serve: prometheus: port: 9000 host: localhost metrics_path: /metrics collapse_request_paths: true ``` The parameter is optional and if not set it defaults to `true`. When set to `true` it modifies the behaviour of the metrics Middleware so that for all the request metrics that contain the `request` label (which is equal to the request context path) its value is collapsed to only the first element of the segment. Eg. ``` curl http://localhost:4456/decisions/service1/users curl http://localhost:4456/decisions/service1/topics ``` will result in the following request metrics (trimmed for reading convenience): ``` # TYPE ory_oathkeeper_request_duration_seconds histogram ory_oathkeeper_request_duration_seconds_count{method="GET",request="/decisions",service="oathkeeper-api",status_code="404"} 2 # HELP ory_oathkeeper_requests_total Total number of requests # TYPE ory_oathkeeper_requests_total counter ory_oathkeeper_requests_total{method="GET",request="/decisions",service="oathkeeper-api",status_code="404"} 2 ``` When `collapse_request_paths` is set to `false` the metrics will keep the path previous fine granularity: ``` # HELP ory_oathkeeper_request_duration_seconds Time spent serving requests. # TYPE ory_oathkeeper_request_duration_seconds histogram ory_oathkeeper_request_duration_seconds_count{method="GET",request="/decisions/service1/topics",service="oathkeeper-api",status_code="404"} 1 ory_oathkeeper_request_duration_seconds_count{method="GET",request="/decisions/service1/users",service="oathkeeper-api",status_code="404"} 1 # HELP ory_oathkeeper_requests_total Total number of requests # TYPE ory_oathkeeper_requests_total counter ory_oathkeeper_requests_total{method="GET",request="/decisions/service1/topics",service="oathkeeper-api",status_code="404"} 1 ory_oathkeeper_requests_total{method="GET",request="/decisions/service1/users",service="oathkeeper-api",status_code="404"} 1 ```
- Loading branch information
1 parent
0185070
commit ddcb226
Showing
8 changed files
with
196 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package metrics | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/julienschmidt/httprouter" | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/prometheus/client_golang/prometheus/testutil" | ||
"github.com/urfave/negroni" | ||
) | ||
|
||
var ( | ||
metricMetadata string = ` | ||
# HELP ory_oathkeeper_requests_total Total number of requests | ||
# TYPE ory_oathkeeper_requests_total counter | ||
` | ||
rootMetric string = ` | ||
ory_oathkeeper_requests_total{method="GET",request="/",service="test",status_code="200"} 1 | ||
` | ||
metricsNotCollapsed string = metricMetadata + rootMetric + ` | ||
ory_oathkeeper_requests_total{method="GET",request="/hello/world",service="test",status_code="200"} 1 | ||
` | ||
metricsCollapsed string = metricMetadata + rootMetric + ` | ||
ory_oathkeeper_requests_total{method="GET",request="/hello",service="test",status_code="200"} 1 | ||
` | ||
serverContextPaths []string = []string{"/", "/hello/world"} | ||
) | ||
|
||
func NewTestPrometheusRepository(collector prometheus.Collector) *PrometheusRepository { | ||
r := prometheus.NewRegistry() | ||
|
||
pr := &PrometheusRepository{ | ||
Registry: r, | ||
metrics: []prometheus.Collector{collector}, | ||
} | ||
|
||
return pr | ||
} | ||
|
||
func PrometheusTestApp(middleware *Middleware) http.Handler { | ||
n := negroni.Classic() | ||
n.Use(middleware) | ||
|
||
r := httprouter.New() | ||
|
||
for _, path := range serverContextPaths { | ||
r.GET(path, func(res http.ResponseWriter, req *http.Request, p httprouter.Params) { | ||
fmt.Fprint(res, "OK") | ||
}) | ||
} | ||
n.UseHandler(r) | ||
return n | ||
} | ||
|
||
var prometheusParams = []struct { | ||
name string | ||
collapsePaths bool | ||
expectedMetrics string | ||
}{ | ||
{"Not collapsed paths", false, metricsNotCollapsed}, | ||
{"Collapsed paths", true, metricsCollapsed}, | ||
} | ||
|
||
func TestPrometheusRequestTotalMetrics(t *testing.T) { | ||
for _, tt := range prometheusParams { | ||
t.Run(tt.name, func(t *testing.T) { | ||
// re-initialize to prevent double counts | ||
RequestTotal.Reset() | ||
|
||
promRepo := NewTestPrometheusRepository(RequestTotal) | ||
promMiddleware := NewMiddleware(promRepo, "test") | ||
promMiddleware.CollapsePaths(tt.collapsePaths) | ||
|
||
ts := httptest.NewServer(PrometheusTestApp(promMiddleware)) | ||
defer ts.Close() | ||
|
||
for _, path := range serverContextPaths { | ||
req, err := http.NewRequest("GET", ts.URL+path, nil) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
client := &http.Client{} | ||
_, err = client.Do(req) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
if err := testutil.CollectAndCompare(RequestTotal, strings.NewReader(tt.expectedMetrics), "ory_oathkeeper_requests_total"); err != nil { | ||
t.Fatal(err) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
var requestURIParams = []struct { | ||
name string | ||
originalPath string | ||
firstSegment string | ||
}{ | ||
{"root path", "/", "/"}, | ||
{"single segment", "/test", "/test"}, | ||
{"two segments", "/test/path", "/test"}, | ||
{"multiple segments", "/test/path/segments", "/test"}, | ||
} | ||
|
||
func TestMiddlewareGetFirstPathSegment(t *testing.T) { | ||
promMiddleware := NewMiddleware(nil, "test") | ||
|
||
for _, tt := range requestURIParams { | ||
t.Run(tt.name, func(t *testing.T) { | ||
promMiddleware.CollapsePaths(true) | ||
collapsed := promMiddleware.getFirstPathSegment(tt.originalPath) | ||
if collapsed != tt.firstSegment { | ||
t.Fatalf("Expected first segment: %s to be equal to: %s", collapsed, tt.firstSegment) | ||
} | ||
}) | ||
} | ||
} |