From f2f0435e7187945239d1a58e659f2a2417a71db5 Mon Sep 17 00:00:00 2001 From: RainbowMango Date: Tue, 3 Dec 2019 17:58:15 +0800 Subject: [PATCH] Enable hidden custom collectors when calling SetShowHidden(). --- .../component-base/metrics/collector.go | 15 ++++ .../k8s.io/component-base/metrics/registry.go | 39 ++++++++- .../component-base/metrics/registry_test.go | 86 +++++++++++++++++++ 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/component-base/metrics/collector.go b/staging/src/k8s.io/component-base/metrics/collector.go index 382ce5ce77d..1f7ecb3de49 100644 --- a/staging/src/k8s.io/component-base/metrics/collector.go +++ b/staging/src/k8s.io/component-base/metrics/collector.go @@ -38,6 +38,9 @@ type StableCollector interface { // Create will initialize all Desc and it intends to be called by registry. Create(version *semver.Version, self StableCollector) bool + // ClearState will clear all the states marked by Create. + ClearState() + // HiddenMetrics tells the list of hidden metrics with fqName. HiddenMetrics() []string } @@ -162,6 +165,18 @@ func (bsc *BaseStableCollector) Create(version *semver.Version, self StableColle return false } +// ClearState will clear all the states marked by Create. +// It intends to be used for re-register a hidden metric. +func (bsc *BaseStableCollector) ClearState() { + for _, d := range bsc.descriptors { + d.ClearState() + } + + bsc.descriptors = nil + bsc.registrable = nil + bsc.hidden = nil +} + // HiddenMetrics tells the list of hidden metrics with fqName. func (bsc *BaseStableCollector) HiddenMetrics() (fqNames []string) { for i := range bsc.hidden { diff --git a/staging/src/k8s.io/component-base/metrics/registry.go b/staging/src/k8s.io/component-base/metrics/registry.go index 4265b6b6663..3ff4826e542 100644 --- a/staging/src/k8s.io/component-base/metrics/registry.go +++ b/staging/src/k8s.io/component-base/metrics/registry.go @@ -83,6 +83,7 @@ func SetShowHidden() { // re-register collectors that has been hidden in phase of last registry. for _, r := range registries { r.enableHiddenCollectors() + r.enableHiddenStableCollectors() } }) } @@ -120,7 +121,7 @@ type KubeRegistry interface { CustomMustRegister(cs ...StableCollector) Register(Registerable) error MustRegister(...Registerable) - Unregister(Registerable) bool + Unregister(collector Collector) bool Gather() ([]*dto.MetricFamily, error) } @@ -216,7 +217,7 @@ func (kr *kubeRegistry) RawMustRegister(cs ...prometheus.Collector) { // returns whether a Collector was unregistered. Note that an unchecked // Collector cannot be unregistered (as its Describe method does not // yield any descriptor). -func (kr *kubeRegistry) Unregister(collector Registerable) bool { +func (kr *kubeRegistry) Unregister(collector Collector) bool { return kr.PromRegistry.Unregister(collector) } @@ -249,14 +250,44 @@ func (kr *kubeRegistry) trackStableCollectors(cs ...StableCollector) { // enableHiddenCollectors will re-register all of the hidden collectors. func (kr *kubeRegistry) enableHiddenCollectors() { + if len(kr.hiddenCollectors) == 0 { + return + } + kr.hiddenCollectorsLock.Lock() - defer kr.hiddenCollectorsLock.Unlock() + cs := make([]Registerable, 0, len(kr.hiddenCollectors)) for _, c := range kr.hiddenCollectors { c.ClearState() - kr.MustRegister(c) + cs = append(cs, c) } + kr.hiddenCollectors = nil + kr.hiddenCollectorsLock.Unlock() + kr.MustRegister(cs...) +} + +// enableHiddenStableCollectors will re-register the stable collectors if there is one or more hidden metrics in it. +// Since we can not register a metrics twice, so we have to unregister first then register again. +func (kr *kubeRegistry) enableHiddenStableCollectors() { + if len(kr.stableCollectors) == 0 { + return + } + + kr.stableCollectorsLock.Lock() + + cs := make([]StableCollector, 0, len(kr.stableCollectors)) + for _, c := range kr.stableCollectors { + if len(c.HiddenMetrics()) > 0 { + kr.Unregister(c) // unregister must happens before clear state, otherwise no metrics would be unregister + c.ClearState() + cs = append(cs, c) + } + } + + kr.stableCollectors = nil + kr.stableCollectorsLock.Unlock() + kr.CustomMustRegister(cs...) } func newKubeRegistry(v apimachineryversion.Info) *kubeRegistry { diff --git a/staging/src/k8s.io/component-base/metrics/registry_test.go b/staging/src/k8s.io/component-base/metrics/registry_test.go index 9058b295bde..4dc225d4eb3 100644 --- a/staging/src/k8s.io/component-base/metrics/registry_test.go +++ b/staging/src/k8s.io/component-base/metrics/registry_test.go @@ -391,3 +391,89 @@ func TestEnableHiddenMetrics(t *testing.T) { }) } } + +func TestEnableHiddenStableCollector(t *testing.T) { + var currentVersion = apimachineryversion.Info{ + Major: "1", + Minor: "17", + GitVersion: "v1.17.0-alpha-1.12345", + } + var normal = NewDesc("test_enable_hidden_custom_metric_normal", "this is a normal metric", []string{"name"}, nil, STABLE, "") + var hiddenA = NewDesc("test_enable_hidden_custom_metric_hidden_a", "this is the hidden metric A", []string{"name"}, nil, STABLE, "1.16.0") + var hiddenB = NewDesc("test_enable_hidden_custom_metric_hidden_b", "this is the hidden metric B", []string{"name"}, nil, STABLE, "1.16.0") + + var tests = []struct { + name string + descriptors []*Desc + metricNames []string + expectMetricsBeforeEnable string + expectMetricsAfterEnable string + }{ + { + name: "all hidden", + descriptors: []*Desc{hiddenA, hiddenB}, + metricNames: []string{"test_enable_hidden_custom_metric_hidden_a", + "test_enable_hidden_custom_metric_hidden_b"}, + expectMetricsBeforeEnable: "", + expectMetricsAfterEnable: ` + # HELP test_enable_hidden_custom_metric_hidden_a [STABLE] (Deprecated since 1.16.0) this is the hidden metric A + # TYPE test_enable_hidden_custom_metric_hidden_a gauge + test_enable_hidden_custom_metric_hidden_a{name="value"} 1 + # HELP test_enable_hidden_custom_metric_hidden_b [STABLE] (Deprecated since 1.16.0) this is the hidden metric B + # TYPE test_enable_hidden_custom_metric_hidden_b gauge + test_enable_hidden_custom_metric_hidden_b{name="value"} 1 + `, + }, + { + name: "partial hidden", + descriptors: []*Desc{normal, hiddenA, hiddenB}, + metricNames: []string{"test_enable_hidden_custom_metric_normal", + "test_enable_hidden_custom_metric_hidden_a", + "test_enable_hidden_custom_metric_hidden_b"}, + expectMetricsBeforeEnable: ` + # HELP test_enable_hidden_custom_metric_normal [STABLE] this is a normal metric + # TYPE test_enable_hidden_custom_metric_normal gauge + test_enable_hidden_custom_metric_normal{name="value"} 1 + `, + expectMetricsAfterEnable: ` + # HELP test_enable_hidden_custom_metric_normal [STABLE] this is a normal metric + # TYPE test_enable_hidden_custom_metric_normal gauge + test_enable_hidden_custom_metric_normal{name="value"} 1 + # HELP test_enable_hidden_custom_metric_hidden_a [STABLE] (Deprecated since 1.16.0) this is the hidden metric A + # TYPE test_enable_hidden_custom_metric_hidden_a gauge + test_enable_hidden_custom_metric_hidden_a{name="value"} 1 + # HELP test_enable_hidden_custom_metric_hidden_b [STABLE] (Deprecated since 1.16.0) this is the hidden metric B + # TYPE test_enable_hidden_custom_metric_hidden_b gauge + test_enable_hidden_custom_metric_hidden_b{name="value"} 1 + `, + }, + } + + for _, test := range tests { + tc := test + t.Run(tc.name, func(t *testing.T) { + registry := newKubeRegistry(currentVersion) + customCollector := newTestCustomCollector(tc.descriptors...) + registry.CustomMustRegister(customCollector) + + if err := testutil.GatherAndCompare(registry, strings.NewReader(tc.expectMetricsBeforeEnable), tc.metricNames...); err != nil { + t.Fatalf("before enable test failed: %v", err) + } + + SetShowHidden() + defer func() { + showHiddenOnce = *new(sync.Once) + showHidden.Store(false) + }() + + if err := testutil.GatherAndCompare(registry, strings.NewReader(tc.expectMetricsAfterEnable), tc.metricNames...); err != nil { + t.Fatalf("after enable test failed: %v", err) + } + + // refresh descriptors so as to share with cases. + for _, d := range tc.descriptors { + d.ClearState() + } + }) + } +}