Fix metrics bucket key high cardinality

This commit is contained in:
Tom Moulard 2022-02-09 09:58:08 +01:00 committed by GitHub
parent 2d56be0ebb
commit 4da33c2bc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 17 deletions

View file

@ -438,3 +438,11 @@ To enable HTTP/3 on an EntryPoint, please check out the [HTTP/3 configuration](.
In `v2.6`, the [Kubernetes Gateway API provider](../providers/kubernetes-gateway.md) now only supports the version [v1alpha2](https://gateway-api.sigs.k8s.io/v1alpha2/guides/getting-started/) of the specification and
[route namespaces](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.RouteNamespaces) selectors, which requires Traefik to fetch and watch the cluster namespaces.
Therefore, the [RBAC](../reference/dynamic-configuration/kubernetes-gateway.md#rbac) and [CRD](../reference/dynamic-configuration/kubernetes-gateway.md#definitions) definitions must be updated.
## v2.6.0 to v2.6.1
In `v2.6.1`, the metrics system does not support any more custom HTTP method verbs to prevent potential metrics cardinality overhead.
In consequence, for metrics having the method label,
if the HTTP method verb of a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`),
the value for the method label becomes `EXTENSION_METHOD`, instead of the request's one.

View file

@ -61,7 +61,7 @@ traefik_config_last_reload_success
The expiration date of certificates.
Available labels: `cn`, `sans`, `serial`.
[Labels](#labels): `cn`, `sans`, `serial`.
```dd tab="Datadog"
tls.certs.notAfterTimestamp
@ -93,7 +93,7 @@ traefik_tls_certs_not_after
The total count of HTTP requests received by an entrypoint.
Available labels: `code`, `method`, `protocol`, `entrypoint`.
[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.total
@ -116,7 +116,7 @@ traefik_entrypoint_requests_total
The total count of HTTPS requests received by an entrypoint.
Available labels: `tls_version`, `tls_cipher`, `entrypoint`.
[Labels](#labels): `tls_version`, `tls_cipher`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.tls.total
@ -139,7 +139,7 @@ traefik_entrypoint_requests_tls_total
Request processing duration histogram on an entrypoint.
Available labels: `code`, `method`, `protocol`, `entrypoint`.
[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.duration
@ -162,7 +162,7 @@ traefik_entrypoint_request_duration_seconds
The current count of open connections on an entrypoint.
Available labels: `method`, `protocol`, `entrypoint`.
[Labels](#labels): `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.connections.open
@ -194,7 +194,7 @@ traefik_entrypoint_open_connections
The total count of HTTP requests handled by a router.
Available labels: `code`, `method`, `protocol`, `router`, `service`.
[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.request.total
@ -217,7 +217,7 @@ traefik_router_requests_total
The total count of HTTPS requests handled by a router.
Available labels: `tls_version`, `tls_cipher`, `router`, `service`.
[Labels](#labels): `tls_version`, `tls_cipher`, `router`, `service`.
```dd tab="Datadog"
router.request.tls.total
@ -240,7 +240,7 @@ traefik_router_requests_tls_total
Request processing duration histogram on a router.
Available labels: `code`, `method`, `protocol`, `router`, `service`.
[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.request.duration
@ -263,7 +263,7 @@ traefik_router_request_duration_seconds
The current count of open connections on a router.
Available labels: `method`, `protocol`, `router`, `service`.
[Labels](#labels): `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.connections.open
@ -297,7 +297,7 @@ traefik_router_open_connections
The total count of HTTP requests processed on a service.
Available labels: `code`, `method`, `protocol`, `service`.
[Labels](#labels): `code`, `method`, `protocol`, `service`.
```dd tab="Datadog"
service.request.total
@ -320,7 +320,7 @@ traefik_service_requests_total
The total count of HTTPS requests processed on a service.
Available labels: `tls_version`, `tls_cipher`, `service`.
[Labels](#labels): `tls_version`, `tls_cipher`, `service`.
```dd tab="Datadog"
router.service.tls.total
@ -343,7 +343,7 @@ traefik_service_requests_tls_total
Request processing duration histogram on a service.
Available labels: `code`, `method`, `protocol`, `service`.
[Labels](#labels): `code`, `method`, `protocol`, `service`.
```dd tab="Datadog"
service.request.duration
@ -366,7 +366,7 @@ traefik_service_request_duration_seconds
The current count of open connections on a service.
Available labels: `method`, `protocol`, `service`.
[Labels](#labels): `method`, `protocol`, `service`.
```dd tab="Datadog"
service.connections.open
@ -389,7 +389,7 @@ traefik_service_open_connections
The count of requests retries on a service.
Available labels: `service`.
[Labels](#labels): `service`.
```dd tab="Datadog"
service.retries.total
@ -412,7 +412,7 @@ traefik_service_retries_total
Current service's server status, described by a gauge with a value of 0 for a down server or a value of 1 for an up server.
Available labels: `service`, `url`.
[Labels](#labels): `service`, `url`.
```dd tab="Datadog"
service.server.up
@ -430,3 +430,28 @@ traefik_service_server_up
# Default prefix: "traefik"
{prefix}.service.server.up
```
## Labels
Here is a comprehensive list of labels that are provided by the metrics:
| Label | Description | example |
|---------------|---------------------------------------|----------------------------|
| `cn` | Certificate Common Name | "example.com" |
| `code` | Request code | "200" |
| `entrypoint` | Entrypoint that handled the request | "example_entrypoint" |
| `method` | Request Method | "GET" |
| `protocol` | Request protocol | "http" |
| `router` | Router that handled the request | "example_router" |
| `sans` | Certificate Subject Alternative NameS | "example.com" |
| `serial` | Certificate Serial Number | "123..." |
| `service` | Service that handled the request | "example_service@provider" |
| `tls_cipher` | TLS cipher used for the request | "TLS_FALLBACK_SCSV" |
| `tls_version` | TLS version used for the request | "1.0" |
| `url` | Service server url | "http://example.com" |
!!! info "`method` label value"
If the HTTP method verb on a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`),
then the value for the method label becomes `EXTENSION_METHOD`.

View file

@ -159,12 +159,27 @@ func containsHeader(req *http.Request, name, value string) bool {
return false
}
// getMethod returns the request's method.
// It checks whether the method is a valid UTF-8 string.
// To restrict the (potentially infinite) number of accepted values for the method,
// and avoid unbounded memory issues,
// values that are not part of the set of HTTP verbs are replaced with EXTENSION_METHOD.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
// https://datatracker.ietf.org/doc/html/rfc2616/#section-5.1.1.
func getMethod(r *http.Request) string {
if !utf8.ValidString(r.Method) {
log.Warnf("Invalid HTTP method encoding: %s", r.Method)
log.WithoutContext().Warnf("Invalid HTTP method encoding: %s", r.Method)
return "NON_UTF8_HTTP_METHOD"
}
return r.Method
switch r.Method {
case "HEAD", "GET", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", // https://datatracker.ietf.org/doc/html/rfc7231#section-4
"PATCH", // https://datatracker.ietf.org/doc/html/rfc5789#section-2
"PRI": // https://datatracker.ietf.org/doc/html/rfc7540#section-11.6
return r.Method
default:
return "EXTENSION_METHOD"
}
}
type retryMetrics interface {

View file

@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
"github.com/go-kit/kit/metrics"
@ -98,3 +99,33 @@ func TestCloseNotifier(t *testing.T) {
})
}
}
func Test_getMethod(t *testing.T) {
testCases := []struct {
method string
expected string
}{
{
method: http.MethodGet,
expected: http.MethodGet,
},
{
method: strings.ToLower(http.MethodGet),
expected: "EXTENSION_METHOD",
},
{
method: "THIS_IS_NOT_A_VALID_METHOD",
expected: "EXTENSION_METHOD",
},
}
for _, test := range testCases {
test := test
t.Run(test.method, func(t *testing.T) {
t.Parallel()
request := httptest.NewRequest(test.method, "http://example.com", nil)
assert.Equal(t, test.expected, getMethod(request))
})
}
}