Cherry-pick #83427
Fix double counting issue for request metrics on timeout. Kubernetes-commit: 02fdb52f0f26d2d13f3f9b63321793740b63c745
This commit is contained in:
parent
3893be10d3
commit
f04a5fe4f8
|
@ -140,7 +140,7 @@ var (
|
|||
},
|
||||
[]string{"group", "version", "kind"},
|
||||
)
|
||||
// Because of volatality of the base metric this is pre-aggregated one. Instead of reporing current usage all the time
|
||||
// Because of volatility of the base metric this is pre-aggregated one. Instead of reporting current usage all the time
|
||||
// it reports maximal usage during the last second.
|
||||
currentInflightRequests = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
|
@ -149,6 +149,15 @@ var (
|
|||
},
|
||||
[]string{"requestKind"},
|
||||
)
|
||||
|
||||
requestTerminationsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "apiserver_request_terminations_total",
|
||||
Help: "Number of requests which apiserver terminated in self-defense.",
|
||||
},
|
||||
[]string{"verb", "group", "version", "resource", "subresource", "scope", "component", "code"},
|
||||
)
|
||||
|
||||
kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`)
|
||||
|
||||
metrics = []resettableCollector{
|
||||
|
@ -163,6 +172,7 @@ var (
|
|||
DeprecatedDroppedRequests,
|
||||
RegisteredWatchers,
|
||||
currentInflightRequests,
|
||||
requestTerminationsTotal,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -196,18 +206,20 @@ func UpdateInflightRequestMetrics(nonmutating, mutating int) {
|
|||
currentInflightRequests.WithLabelValues(MutatingKind).Set(float64(mutating))
|
||||
}
|
||||
|
||||
// Record records a single request to the standard metrics endpoints. For use by handlers that perform their own
|
||||
// processing. All API paths should use InstrumentRouteFunc implicitly. Use this instead of MonitorRequest if
|
||||
// you already have a RequestInfo object.
|
||||
func Record(req *http.Request, requestInfo *request.RequestInfo, component, contentType string, code int, responseSizeInBytes int, elapsed time.Duration) {
|
||||
// RecordRequestTermination records that the request was terminated early as part of a resource
|
||||
// preservation or apiserver self-defense mechanism (e.g. timeouts, maxinflight throttling,
|
||||
// proxyHandler errors). RecordRequestTermination should only be called zero or one times
|
||||
// per request.
|
||||
func RecordRequestTermination(req *http.Request, requestInfo *request.RequestInfo, component string, code int) {
|
||||
if requestInfo == nil {
|
||||
requestInfo = &request.RequestInfo{Verb: req.Method, Path: req.URL.Path}
|
||||
}
|
||||
scope := CleanScope(requestInfo)
|
||||
verb := canonicalVerb(strings.ToUpper(req.Method), scope)
|
||||
if requestInfo.IsResourceRequest {
|
||||
MonitorRequest(req, strings.ToUpper(requestInfo.Verb), requestInfo.APIGroup, requestInfo.APIVersion, requestInfo.Resource, requestInfo.Subresource, scope, component, contentType, code, responseSizeInBytes, elapsed)
|
||||
requestTerminationsTotal.WithLabelValues(cleanVerb(verb, req), requestInfo.APIGroup, requestInfo.APIVersion, requestInfo.Resource, requestInfo.Subresource, scope, component, codeToString(code)).Inc()
|
||||
} else {
|
||||
MonitorRequest(req, strings.ToUpper(requestInfo.Verb), "", "", "", requestInfo.Path, scope, component, contentType, code, responseSizeInBytes, elapsed)
|
||||
requestTerminationsTotal.WithLabelValues(cleanVerb(verb, req), "", "", "", requestInfo.Path, scope, component, codeToString(code)).Inc()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,6 +323,18 @@ func CleanScope(requestInfo *request.RequestInfo) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func canonicalVerb(verb string, scope string) string {
|
||||
switch verb {
|
||||
case "GET", "HEAD":
|
||||
if scope != "resource" {
|
||||
return "LIST"
|
||||
}
|
||||
return "GET"
|
||||
default:
|
||||
return verb
|
||||
}
|
||||
}
|
||||
|
||||
func cleanVerb(verb string, request *http.Request) string {
|
||||
reportedVerb := verb
|
||||
if verb == "LIST" {
|
||||
|
|
|
@ -178,7 +178,7 @@ func WithMaxInFlightLimit(
|
|||
}
|
||||
}
|
||||
}
|
||||
metrics.Record(r, requestInfo, metrics.APIServerComponent, "", http.StatusTooManyRequests, 0, 0)
|
||||
metrics.RecordRequestTermination(r, requestInfo, metrics.APIServerComponent, http.StatusTooManyRequests)
|
||||
tooManyRequests(r, w)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning apir
|
|||
|
||||
postTimeoutFn := func() {
|
||||
cancel()
|
||||
metrics.Record(req, requestInfo, metrics.APIServerComponent, "", http.StatusGatewayTimeout, 0, 0)
|
||||
metrics.RecordRequestTermination(req, requestInfo, metrics.APIServerComponent, http.StatusGatewayTimeout)
|
||||
}
|
||||
return req, time.After(timeout), postTimeoutFn, apierrors.NewTimeoutError(fmt.Sprintf("request did not complete within %s", timeout), 0)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue