diff --git a/pkg/util/metrics/BUILD b/pkg/util/metrics/BUILD index f6ebcabce7b..a15d30ec247 100644 --- a/pkg/util/metrics/BUILD +++ b/pkg/util/metrics/BUILD @@ -34,9 +34,6 @@ filegroup( filegroup( name = "all-srcs", - srcs = [ - ":package-srcs", - "//pkg/util/metrics/framework:all-srcs", - ], + srcs = [":package-srcs"], tags = ["automanaged"], ) diff --git a/staging/src/k8s.io/component-base/BUILD b/staging/src/k8s.io/component-base/BUILD index 69be7ee4959..68ac5d60057 100644 --- a/staging/src/k8s.io/component-base/BUILD +++ b/staging/src/k8s.io/component-base/BUILD @@ -13,6 +13,7 @@ filegroup( "//staging/src/k8s.io/component-base/cli/globalflag:all-srcs", "//staging/src/k8s.io/component-base/config:all-srcs", "//staging/src/k8s.io/component-base/logs:all-srcs", + "//staging/src/k8s.io/component-base/metrics:all-srcs", ], tags = ["automanaged"], visibility = ["//visibility:public"], diff --git a/pkg/util/metrics/framework/BUILD b/staging/src/k8s.io/component-base/metrics/BUILD similarity index 92% rename from pkg/util/metrics/framework/BUILD rename to staging/src/k8s.io/component-base/metrics/BUILD index 1314bbde4a1..30e6181eb99 100644 --- a/pkg/util/metrics/framework/BUILD +++ b/staging/src/k8s.io/component-base/metrics/BUILD @@ -16,9 +16,9 @@ go_library( "version_parser.go", "wrappers.go", ], - importpath = "k8s.io/kubernetes/pkg/util/metrics/framework", + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics", + importpath = "k8s.io/component-base/metrics", deps = [ - "//pkg/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/github.com/blang/semver:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", diff --git a/pkg/util/metrics/framework/counter.go b/staging/src/k8s.io/component-base/metrics/counter.go similarity index 99% rename from pkg/util/metrics/framework/counter.go rename to staging/src/k8s.io/component-base/metrics/counter.go index a2e3ab5455c..0d4e7fb3f24 100644 --- a/pkg/util/metrics/framework/counter.go +++ b/staging/src/k8s.io/component-base/metrics/counter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "github.com/blang/semver" diff --git a/pkg/util/metrics/framework/counter_test.go b/staging/src/k8s.io/component-base/metrics/counter_test.go similarity index 94% rename from pkg/util/metrics/framework/counter_test.go rename to staging/src/k8s.io/component-base/metrics/counter_test.go index 26db8c1c5ac..79fd30cdbd8 100644 --- a/pkg/util/metrics/framework/counter_test.go +++ b/staging/src/k8s.io/component-base/metrics/counter_test.go @@ -14,22 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "bytes" "github.com/blang/semver" "github.com/prometheus/common/expfmt" + apimachineryversion "k8s.io/apimachinery/pkg/version" "testing" ) func TestCounter(t *testing.T) { - v115 := semver.MustParse("1.15.0") v114 := semver.MustParse("1.14.0") + v115 := semver.MustParse("1.15.0") var tests = []struct { desc string *CounterOpts - registryVersion *semver.Version expectedMetricCount int expectedHelp string }{ @@ -42,7 +42,6 @@ func TestCounter(t *testing.T) { StabilityLevel: ALPHA, Help: "counter help", }, - registryVersion: &v115, expectedMetricCount: 1, expectedHelp: "[ALPHA] counter help", }, @@ -56,7 +55,6 @@ func TestCounter(t *testing.T) { StabilityLevel: ALPHA, DeprecatedVersion: &v115, }, - registryVersion: &v115, expectedMetricCount: 1, expectedHelp: "[ALPHA] (Deprecated since 1.15.0) counter help", }, @@ -70,14 +68,17 @@ func TestCounter(t *testing.T) { StabilityLevel: ALPHA, DeprecatedVersion: &v114, }, - registryVersion: &v115, expectedMetricCount: 0, }, } for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - registry := newKubeRegistry(*test.registryVersion) + registry := newKubeRegistry(&apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + }) c := NewCounter(test.CounterOpts) registry.MustRegister(c) @@ -141,7 +142,6 @@ func TestCounterVec(t *testing.T) { Help: "counter help", }, labels: []string{"label_a", "label_b"}, - registryVersion: &v115, expectedMetricFamilyCount: 1, expectedHelp: "counter help", }, @@ -155,7 +155,6 @@ func TestCounterVec(t *testing.T) { DeprecatedVersion: &v115, }, labels: []string{"label_a", "label_b"}, - registryVersion: &v115, expectedMetricFamilyCount: 1, expectedHelp: "(Deprecated since 1.15.0) counter help", }, @@ -169,7 +168,6 @@ func TestCounterVec(t *testing.T) { DeprecatedVersion: &v114, }, labels: []string{"label_a", "label_b"}, - registryVersion: &v115, expectedMetricFamilyCount: 0, expectedHelp: "counter help", }, @@ -177,7 +175,11 @@ func TestCounterVec(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - registry := newKubeRegistry(*test.registryVersion) + registry := newKubeRegistry(&apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + }) c := NewCounterVec(test.CounterOpts, test.labels) registry.MustRegister(c) c.WithLabelValues("1", "2").Inc() diff --git a/pkg/util/metrics/framework/metric.go b/staging/src/k8s.io/component-base/metrics/metric.go similarity index 99% rename from pkg/util/metrics/framework/metric.go rename to staging/src/k8s.io/component-base/metrics/metric.go index e9733dbf1ed..4d5bbf85289 100644 --- a/pkg/util/metrics/framework/metric.go +++ b/staging/src/k8s.io/component-base/metrics/metric.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "github.com/blang/semver" diff --git a/pkg/util/metrics/framework/opts.go b/staging/src/k8s.io/component-base/metrics/opts.go similarity index 99% rename from pkg/util/metrics/framework/opts.go rename to staging/src/k8s.io/component-base/metrics/opts.go index 315e8055eee..1409f241020 100644 --- a/pkg/util/metrics/framework/opts.go +++ b/staging/src/k8s.io/component-base/metrics/opts.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "fmt" diff --git a/pkg/util/metrics/framework/registry.go b/staging/src/k8s.io/component-base/metrics/registry.go similarity index 57% rename from pkg/util/metrics/framework/registry.go rename to staging/src/k8s.io/component-base/metrics/registry.go index 2f31aa4f167..0b67308845d 100644 --- a/pkg/util/metrics/framework/registry.go +++ b/staging/src/k8s.io/component-base/metrics/registry.go @@ -14,38 +14,72 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "github.com/blang/semver" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" - "k8s.io/klog" - "k8s.io/kubernetes/pkg/version" + apimachineryversion "k8s.io/apimachinery/pkg/version" + "sync" ) -// DefaultGlobalRegistry is a stub for the global registry which prometheus client -// currently uses. -var DefaultGlobalRegistry = NewKubeRegistry() +var globalRegistryFactory = metricsRegistryFactory{ + globalRegistry: &noopKubeRegistry{}, +} -// KubeRegistry is a wrapper around a prometheus registry-type object. Upon initialization +// NewKubeRegistry creates a new kubernetes metric registry, loading in the kubernetes +// version information available to the binary. +func (r metricsRegistryFactory) newKubeRegistry() KubeRegistry { + if r.kubeVersion == nil { + return noopKubeRegistry{} + } + return newKubeRegistry(r.kubeVersion) +} + +type metricsRegistryFactory struct { + globalRegistry KubeRegistry + kubeVersion *apimachineryversion.Info + setVersionOnce sync.Once +} + +// KubeRegistry is an interface which implements a subset of prometheus.Registerer and +// prometheus.Gatherer interfaces +type KubeRegistry interface { + Register(KubeCollector) error + MustRegister(...KubeCollector) + Unregister(KubeCollector) bool + Gather() ([]*dto.MetricFamily, error) +} + +// kubeRegistry is a wrapper around a prometheus registry-type object. Upon initialization // the kubernetes binary version information is loaded into the registry object, so that // automatic behavior can be configured for metric versioning. -type KubeRegistry struct { +type kubeRegistry struct { PromRegistry version semver.Version } +// SetRegistryFactoryVersion sets the kubernetes version information for all +// subsequent metrics registry initializations. Only the first call has an effect. +// If a version is not set, then metrics registry creation will no-opt +func SetRegistryFactoryVersion(ver *apimachineryversion.Info) { + globalRegistryFactory.setVersionOnce.Do(func() { + globalRegistryFactory.globalRegistry = newKubeRegistry(ver) + globalRegistryFactory.kubeVersion = ver + }) +} + // Register registers a collectable metric, but it uses a global registry. func Register(c KubeCollector) error { - return DefaultGlobalRegistry.Register(c) + return globalRegistryFactory.globalRegistry.Register(c) } // MustRegister works like Register but registers any number of // Collectors and panics upon the first registration that causes an // error. func MustRegister(cs ...KubeCollector) { - DefaultGlobalRegistry.MustRegister(cs...) + globalRegistryFactory.globalRegistry.MustRegister(cs...) } // Register registers a new Collector to be included in metrics @@ -53,7 +87,7 @@ func MustRegister(cs ...KubeCollector) { // Collector are invalid or if they — in combination with descriptors of // already registered Collectors — do not fulfill the consistency and // uniqueness criteria described in the documentation of metric.Desc. -func (kr *KubeRegistry) Register(c KubeCollector) error { +func (kr *kubeRegistry) Register(c KubeCollector) error { if c.Create(&kr.version) { return kr.PromRegistry.Register(c) } @@ -63,7 +97,7 @@ func (kr *KubeRegistry) Register(c KubeCollector) error { // MustRegister works like Register but registers any number of // Collectors and panics upon the first registration that causes an // error. -func (kr *KubeRegistry) MustRegister(cs ...KubeCollector) { +func (kr *kubeRegistry) MustRegister(cs ...KubeCollector) { metrics := make([]prometheus.Collector, 0, len(cs)) for _, c := range cs { if c.Create(&kr.version) { @@ -79,7 +113,7 @@ func (kr *KubeRegistry) MustRegister(cs ...KubeCollector) { // 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 KubeCollector) bool { +func (kr *kubeRegistry) Unregister(collector KubeCollector) bool { return kr.PromRegistry.Unregister(collector) } @@ -90,28 +124,31 @@ func (kr *KubeRegistry) Unregister(collector KubeCollector) bool { // for valid exposition. As an exception to the strict consistency // requirements described for metric.Desc, Gather will tolerate // different sets of label names for metrics of the same metric family. -func (kr *KubeRegistry) Gather() ([]*dto.MetricFamily, error) { +func (kr *kubeRegistry) Gather() ([]*dto.MetricFamily, error) { return kr.PromRegistry.Gather() } // NewKubeRegistry creates a new kubernetes metric registry, loading in the kubernetes // version information available to the binary. -func NewKubeRegistry() *KubeRegistry { - v, err := parseVersion(version.Get()) - if err != nil { - klog.Fatalf("Can't initialize a registry without a valid version %v", err) - } - if v == nil { - klog.Fatalf("No valid version loaded for metrics registry") - } - return newKubeRegistry(semver.MustParse(*v)) +func NewKubeRegistry() KubeRegistry { + return globalRegistryFactory.newKubeRegistry() } // newKubeRegistry creates a new vanilla Registry without any Collectors // pre-registered. -func newKubeRegistry(version semver.Version) *KubeRegistry { - return &KubeRegistry{ +func newKubeRegistry(v *apimachineryversion.Info) KubeRegistry { + return &kubeRegistry{ PromRegistry: prometheus.NewRegistry(), - version: version, + version: parseVersion(*v), } } + +// noop registry +var noopRegistry = &noopKubeRegistry{} + +type noopKubeRegistry struct{} + +func (noopKubeRegistry) Register(KubeCollector) error { return nil } +func (noopKubeRegistry) MustRegister(...KubeCollector) {} +func (noopKubeRegistry) Unregister(KubeCollector) bool { return false } +func (noopKubeRegistry) Gather() ([]*dto.MetricFamily, error) { return nil, nil } diff --git a/pkg/util/metrics/framework/registry_test.go b/staging/src/k8s.io/component-base/metrics/registry_test.go similarity index 94% rename from pkg/util/metrics/framework/registry_test.go rename to staging/src/k8s.io/component-base/metrics/registry_test.go index 7b4d09a5395..020cca747f2 100644 --- a/pkg/util/metrics/framework/registry_test.go +++ b/staging/src/k8s.io/component-base/metrics/registry_test.go @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "github.com/blang/semver" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" + apimachineryversion "k8s.io/apimachinery/pkg/version" "testing" ) @@ -116,7 +117,11 @@ func TestRegister(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - registry := newKubeRegistry(*test.registryVersion) + registry := newKubeRegistry(&apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + }) for i, m := range test.metrics { err := registry.Register(m) if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() { @@ -183,7 +188,11 @@ func TestMustRegister(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - registry := newKubeRegistry(*test.registryVersion) + registry := newKubeRegistry(&apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + }) for i, m := range test.metrics { if test.expectedPanics[i] { assert.Panics(t, diff --git a/pkg/util/metrics/framework/version_parser.go b/staging/src/k8s.io/component-base/metrics/version_parser.go similarity index 75% rename from pkg/util/metrics/framework/version_parser.go rename to staging/src/k8s.io/component-base/metrics/version_parser.go index 2d94f33c0d3..7ef66d08a22 100644 --- a/pkg/util/metrics/framework/version_parser.go +++ b/staging/src/k8s.io/component-base/metrics/version_parser.go @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "fmt" + "github.com/blang/semver" apimachineryversion "k8s.io/apimachinery/pkg/version" "regexp" ) @@ -30,11 +31,11 @@ var ( versionRe = regexp.MustCompile(versionRegexpString) ) -func parseVersion(ver apimachineryversion.Info) (*string, error) { +func parseVersion(ver apimachineryversion.Info) semver.Version { matches := versionRe.FindAllStringSubmatch(ver.String(), -1) if len(matches) != 1 { - return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", ver.String(), versionRe.String()) + panic(fmt.Sprintf("version string \"%v\" doesn't match expected regular expression: \"%v\"", ver.String(), versionRe.String())) } - return &matches[0][1], nil + return semver.MustParse(matches[0][1]) } diff --git a/pkg/util/metrics/framework/version_parser_test.go b/staging/src/k8s.io/component-base/metrics/version_parser_test.go similarity index 82% rename from pkg/util/metrics/framework/version_parser_test.go rename to staging/src/k8s.io/component-base/metrics/version_parser_test.go index ac02ae5bb77..735053c1126 100644 --- a/pkg/util/metrics/framework/version_parser_test.go +++ b/staging/src/k8s.io/component-base/metrics/version_parser_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( apimachineryversion "k8s.io/apimachinery/pkg/version" @@ -44,12 +44,9 @@ func TestVersionParsing(t *testing.T) { version := apimachineryversion.Info{ GitVersion: test.versionString, } - parsedV, err := parseVersion(version) - if err != nil { - t.Fatalf("Should be able to parse %v", version) - } - if test.expectedVersion != *parsedV { - t.Errorf("Got %v, wanted %v", *parsedV, test.expectedVersion) + parsedV := parseVersion(version) + if test.expectedVersion != parsedV.String() { + t.Errorf("Got %v, wanted %v", parsedV.String(), test.expectedVersion) } }) } diff --git a/pkg/util/metrics/framework/wrappers.go b/staging/src/k8s.io/component-base/metrics/wrappers.go similarity index 99% rename from pkg/util/metrics/framework/wrappers.go rename to staging/src/k8s.io/component-base/metrics/wrappers.go index fa790b090c5..5bb72cacfbc 100644 --- a/pkg/util/metrics/framework/wrappers.go +++ b/staging/src/k8s.io/component-base/metrics/wrappers.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package framework +package metrics import ( "github.com/prometheus/client_golang/prometheus"