Merge pull request #112740 from logicalhan/health-check-metrics

use generic slis as entrypoint for healthcheck metrics
This commit is contained in:
Kubernetes Prow Robot 2022-09-26 16:08:25 -07:00 committed by GitHub
commit d39c9aeff0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 21 deletions

View File

@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package health
package slis
import (
"context"
"errors"
k8smetrics "k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
)
type HealthcheckStatus string
@ -64,12 +63,11 @@ var (
)
statuses = []HealthcheckStatus{Success, Error, Pending}
statusSet = map[HealthcheckStatus]struct{}{Success: {}, Error: {}, Pending: {}}
checkSet = map[HealthcheckType]struct{}{Livez: {}, Readyz: {}, Healthz: {}}
)
func init() {
legacyregistry.MustRegister(healthcheck)
legacyregistry.MustRegister(healthchecksTotal)
func Register(registry k8smetrics.KubeRegistry) {
registry.Register(healthcheck)
registry.Register(healthchecksTotal)
}
func ResetHealthMetrics() {
@ -77,19 +75,16 @@ func ResetHealthMetrics() {
healthchecksTotal.Reset()
}
func ObserveHealthcheck(ctx context.Context, name string, healthcheckType HealthcheckType, status HealthcheckStatus) error {
func ObserveHealthcheck(ctx context.Context, name string, healthcheckType string, status HealthcheckStatus) error {
if _, ok := statusSet[status]; !ok {
return errors.New("not a valid healthcheck status")
}
if _, ok := checkSet[healthcheckType]; !ok {
return errors.New("not a valid healthcheck type")
}
for _, s := range statuses {
if status != s {
healthcheck.WithContext(ctx).WithLabelValues(name, string(healthcheckType), string(s)).Set(0)
healthcheck.WithContext(ctx).WithLabelValues(name, healthcheckType, string(s)).Set(0)
}
}
healthchecksTotal.WithContext(ctx).WithLabelValues(name, string(healthcheckType), string(status)).Inc()
healthcheck.WithContext(ctx).WithLabelValues(name, string(healthcheckType), string(status)).Set(1)
healthchecksTotal.WithContext(ctx).WithLabelValues(name, healthcheckType, string(status)).Inc()
healthcheck.WithContext(ctx).WithLabelValues(name, healthcheckType, string(status)).Set(1)
return nil
}

View File

@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package health
package slis
import (
"context"
"strings"
"testing"
"k8s.io/component-base/metrics/legacyregistry"
"k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/testutil"
)
@ -30,8 +30,10 @@ var (
)
func TestObserveHealthcheck(t *testing.T) {
defer legacyregistry.Reset()
registry := metrics.NewKubeRegistry()
defer registry.Reset()
defer ResetHealthMetrics()
Register(registry)
initialState := Error
healthcheckName := "healthcheck-a"
initialOutput := `
@ -47,14 +49,14 @@ func TestObserveHealthcheck(t *testing.T) {
testCases := []struct {
desc string
name string
hcType HealthcheckType
hcType string
hcStatus HealthcheckStatus
want string
}{
{
desc: "test pending",
name: healthcheckName,
hcType: Healthz,
hcType: "healthz",
hcStatus: Pending,
want: `
# HELP kubernetes_healthcheck [ALPHA] This metric records the result of a single healthcheck.
@ -71,7 +73,7 @@ func TestObserveHealthcheck(t *testing.T) {
{
desc: "test success",
name: healthcheckName,
hcType: Healthz,
hcType: "healthz",
hcStatus: Success,
want: `
# HELP kubernetes_healthcheck [ALPHA] This metric records the result of a single healthcheck.
@ -95,7 +97,7 @@ func TestObserveHealthcheck(t *testing.T) {
if err != nil {
t.Errorf("unexpected err: %v", err)
}
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(initialOutput), testedMetrics...); err != nil {
if err := testutil.GatherAndCompare(registry, strings.NewReader(initialOutput), testedMetrics...); err != nil {
t.Fatal(err)
}
// now record that we successfully purge state
@ -103,7 +105,7 @@ func TestObserveHealthcheck(t *testing.T) {
if err != nil {
t.Errorf("unexpected err: %v", err)
}
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(test.want), testedMetrics...); err != nil {
if err := testutil.GatherAndCompare(registry, strings.NewReader(test.want), testedMetrics...); err != nil {
t.Fatal(err)
}
})

View File

@ -0,0 +1,27 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package slis
import (
"k8s.io/component-base/metrics"
)
var (
// Registry exposes the SLI registry so that additional SLIs can be
// added on a per-component basis.
Registry = metrics.NewKubeRegistry()
)

View File

@ -0,0 +1,53 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package slis
import (
"net/http"
"sync"
"k8s.io/component-base/metrics"
)
var (
installOnce = sync.Once{}
installWithResetOnce = sync.Once{}
)
type mux interface {
Handle(path string, handler http.Handler)
}
type SLIMetrics struct{}
// Install adds the DefaultMetrics handler
func (s SLIMetrics) Install(m mux) {
installOnce.Do(func() {
Register(Registry)
m.Handle("/metrics/slis", metrics.HandlerFor(Registry, metrics.HandlerOpts{}))
})
}
type SLIMetricsWithReset struct{}
// Install adds the DefaultMetrics handler
func (s SLIMetricsWithReset) Install(m mux) {
installWithResetOnce.Do(func() {
Register(Registry)
m.Handle("/metrics/slis", metrics.HandlerWithReset(Registry, metrics.HandlerOpts{}))
})
}

View File

@ -145,6 +145,12 @@ type Gatherer interface {
prometheus.Gatherer
}
// Registerer is the interface for the part of a registry in charge of registering
// the collected metrics.
type Registerer interface {
prometheus.Registerer
}
// GaugeFunc is a Gauge whose value is determined at collect time by calling a
// provided function.
//