move global registry code into subdirectory 'legacyregistry'

This commit is contained in:
Han Kang 2019-05-06 12:29:57 -07:00
parent 04db3dc9f7
commit 7b619f5763
8 changed files with 341 additions and 80 deletions

View File

@ -53,6 +53,9 @@ filegroup(
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
srcs = [
":package-srcs",
"//staging/src/k8s.io/component-base/metrics/legacyregistry:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -74,7 +74,7 @@ func TestCounter(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := newKubeRegistry(&apimachineryversion.Info{
registry := NewKubeRegistry(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",
@ -175,7 +175,7 @@ func TestCounterVec(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := newKubeRegistry(&apimachineryversion.Info{
registry := NewKubeRegistry(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",

View File

@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["registry.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics/legacyregistry",
importpath = "k8s.io/component-base/metrics/legacyregistry",
deps = [
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/component-base/metrics:go_default_library",
"//vendor/github.com/prometheus/client_model/go:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["registry_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/component-base/metrics:go_default_library",
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
)

View File

@ -0,0 +1,89 @@
/*
Copyright 2019 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 legacyregistry
import (
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/component-base/metrics"
"sync"
)
var globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
}
type metricsRegistryFactory struct {
globalRegistry metrics.KubeRegistry
kubeVersion *apimachineryversion.Info
registrationLock sync.Mutex
registerQueue []metrics.KubeCollector
mustRegisterQueue []metrics.KubeCollector
}
// 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) []error {
globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock()
if globalRegistryFactory.kubeVersion != nil {
return nil
}
registrationErrs := make([]error, 0)
globalRegistryFactory.globalRegistry = metrics.NewKubeRegistry(ver)
globalRegistryFactory.kubeVersion = ver
for _, c := range globalRegistryFactory.registerQueue {
err := globalRegistryFactory.globalRegistry.Register(c)
if err != nil {
registrationErrs = append(registrationErrs, err)
}
}
for _, c := range globalRegistryFactory.mustRegisterQueue {
globalRegistryFactory.globalRegistry.MustRegister(c)
}
return registrationErrs
}
// Register registers a collectable metric, but it uses a global registry. Registration is deferred
// until the global registry has a version to use.
func Register(c metrics.KubeCollector) error {
globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock()
if globalRegistryFactory.kubeVersion != nil {
return globalRegistryFactory.globalRegistry.Register(c)
}
globalRegistryFactory.registerQueue = append(globalRegistryFactory.registerQueue, c)
return nil
}
// MustRegister works like Register but registers any number of
// Collectors and panics upon the first registration that causes an
// error. Registration is deferred until the global registry has a version to use.
func MustRegister(cs ...metrics.KubeCollector) {
globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock()
if globalRegistryFactory.kubeVersion != nil {
globalRegistryFactory.globalRegistry.MustRegister(cs...)
return
}
for _, c := range cs {
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c)
}
}

View File

@ -0,0 +1,195 @@
/*
Copyright 2019 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 legacyregistry
import (
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"k8s.io/component-base/metrics"
"testing"
apimachineryversion "k8s.io/apimachinery/pkg/version"
)
func init() {
SetRegistryFactoryVersion(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",
})
}
var (
v115 = semver.MustParse("1.15.0")
v114 = semver.MustParse("1.14.0")
alphaCounter = metrics.NewCounter(
&metrics.CounterOpts{
Namespace: "some_namespace",
Name: "test_counter_name",
Subsystem: "subsystem",
StabilityLevel: metrics.ALPHA,
Help: "counter help",
},
)
alphaDeprecatedCounter = metrics.NewCounter(
&metrics.CounterOpts{
Namespace: "some_namespace",
Name: "test_alpha_dep_counter",
Subsystem: "subsystem",
StabilityLevel: metrics.ALPHA,
Help: "counter help",
DeprecatedVersion: &v115,
},
)
alphaHiddenCounter = metrics.NewCounter(
&metrics.CounterOpts{
Namespace: "some_namespace",
Name: "test_alpha_hidden_counter",
Subsystem: "subsystem",
StabilityLevel: metrics.ALPHA,
Help: "counter help",
DeprecatedVersion: &v114,
},
)
)
func TestRegister(t *testing.T) {
var tests = []struct {
desc string
metrics []*metrics.Counter
registryVersion *semver.Version
expectedErrors []error
expectedIsCreatedValues []bool
expectedIsDeprecated []bool
expectedIsHidden []bool
}{
{
desc: "test registering same metric multiple times",
metrics: []*metrics.Counter{alphaCounter, alphaCounter},
expectedErrors: []error{nil, prometheus.AlreadyRegisteredError{}},
expectedIsCreatedValues: []bool{true, true},
expectedIsDeprecated: []bool{false, false},
expectedIsHidden: []bool{false, false},
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
//t.Errorf("len %v - %v\n", len(test.metrics), len(test.expectedErrors))
for i, m := range test.metrics {
//t.Errorf("m %v\n", m)
err := Register(m)
if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() {
t.Errorf("Got unexpected error %v, wanted %v", err, test.expectedErrors[i])
}
if m.IsCreated() != test.expectedIsCreatedValues[i] {
t.Errorf("Got isCreated == %v, wanted isCreated to be %v", m.IsCreated(), test.expectedIsCreatedValues[i])
}
if m.IsDeprecated() != test.expectedIsDeprecated[i] {
t.Errorf("Got IsDeprecated == %v, wanted IsDeprecated to be %v", m.IsDeprecated(), test.expectedIsDeprecated[i])
}
if m.IsHidden() != test.expectedIsHidden[i] {
t.Errorf("Got IsHidden == %v, wanted IsHidden to be %v", m.IsHidden(), test.expectedIsDeprecated[i])
}
}
})
}
}
func TestMustRegister(t *testing.T) {
var tests = []struct {
desc string
metrics []*metrics.Counter
registryVersion *semver.Version
expectedPanics []bool
}{
{
desc: "test must registering same deprecated metric",
metrics: []*metrics.Counter{alphaDeprecatedCounter, alphaDeprecatedCounter},
expectedPanics: []bool{false, true},
},
{
desc: "test alpha hidden metric",
metrics: []*metrics.Counter{alphaHiddenCounter},
expectedPanics: []bool{false},
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
for i, m := range test.metrics {
if test.expectedPanics[i] {
assert.Panics(t,
func() { MustRegister(m) },
"Did not panic even though we expected it.")
} else {
MustRegister(m)
}
}
})
}
}
func TestDeferredRegister(t *testing.T) {
// reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
}
var err error
err = Register(alphaDeprecatedCounter)
if err != nil {
t.Errorf("Got err == %v, expected no error", err)
}
err = Register(alphaDeprecatedCounter)
if err != nil {
t.Errorf("Got err == %v, expected no error", err)
}
// set the global registry version
errs := SetRegistryFactoryVersion(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",
})
if len(errs) != 1 {
t.Errorf("Got %d errs, expected 1", len(errs))
for _, err := range errs {
t.Logf("\t Got %v", err)
}
}
}
func TestDeferredMustRegister(t *testing.T) {
// reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
}
MustRegister(alphaDeprecatedCounter)
MustRegister(alphaDeprecatedCounter)
assert.Panics(t,
func() {
SetRegistryFactoryVersion(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",
})
},
"Did not panic even though we expected it.")
}

View File

@ -32,7 +32,7 @@ method call depending on whether the metric is deprecated or not.
*/
type KubeCollector interface {
Collector
LazyMetric
lazyKubeMetric
DeprecatedVersion() *semver.Version
// Each collector metric should provide an initialization function
// for both deprecated and non-deprecated variants of a metric. This
@ -43,11 +43,11 @@ type KubeCollector interface {
}
/*
LazyMetric defines our registration functionality. LazyMetric objects are expected
lazyKubeMetric defines our metric registration interface. lazyKubeMetric objects are expected
to lazily instantiate metrics (i.e defer metric instantiation until when
the Create() function is explicitly called).
*/
type LazyMetric interface {
type lazyKubeMetric interface {
Create(*semver.Version) bool
IsCreated() bool
IsHidden() bool
@ -55,7 +55,7 @@ type LazyMetric interface {
}
/*
lazyMetric implements LazyMetric. A lazy metric is lazy because it waits until metric
lazyMetric implements lazyKubeMetric. A lazy metric is lazy because it waits until metric
registration time before instantiation. Add it as an anonymous field to a struct that
implements KubeCollector to get deferred registration behavior. You must call lazyInit
with the KubeCollector itself as an argument.

View File

@ -21,28 +21,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"sync"
)
var globalRegistryFactory = metricsRegistryFactory{
globalRegistry: &noopKubeRegistry{},
}
// 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 {
@ -60,28 +40,6 @@ type kubeRegistry struct {
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 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) {
globalRegistryFactory.globalRegistry.MustRegister(cs...)
}
// Register registers a new Collector to be included in metrics
// collection. It returns an error if the descriptors provided by the
// Collector are invalid or if they — in combination with descriptors of
@ -128,27 +86,11 @@ 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 {
return globalRegistryFactory.newKubeRegistry()
}
// newKubeRegistry creates a new vanilla Registry without any Collectors
// NewKubeRegistry creates a new vanilla Registry without any Collectors
// pre-registered.
func newKubeRegistry(v *apimachineryversion.Info) KubeRegistry {
func NewKubeRegistry(v *apimachineryversion.Info) KubeRegistry {
return &kubeRegistry{
PromRegistry: prometheus.NewRegistry(),
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 }

View File

@ -56,15 +56,6 @@ var (
DeprecatedVersion: &v114,
},
)
stableCounter = NewCounter(
&CounterOpts{
Namespace: "some_namespace",
Name: "test_some_other_counter",
Subsystem: "subsystem",
StabilityLevel: STABLE,
Help: "counter help",
},
)
)
func TestRegister(t *testing.T) {
@ -99,7 +90,7 @@ func TestRegister(t *testing.T) {
desc: "test alpha deprecated metric",
metrics: []*Counter{alphaDeprecatedCounter},
registryVersion: &v115,
expectedErrors: []error{nil, prometheus.AlreadyRegisteredError{}},
expectedErrors: []error{nil},
expectedIsCreatedValues: []bool{true},
expectedIsDeprecated: []bool{true},
expectedIsHidden: []bool{false},
@ -108,7 +99,7 @@ func TestRegister(t *testing.T) {
desc: "test alpha hidden metric",
metrics: []*Counter{alphaHiddenCounter},
registryVersion: &v115,
expectedErrors: []error{nil, prometheus.AlreadyRegisteredError{}},
expectedErrors: []error{nil},
expectedIsCreatedValues: []bool{false},
expectedIsDeprecated: []bool{true},
expectedIsHidden: []bool{true},
@ -117,7 +108,7 @@ func TestRegister(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := newKubeRegistry(&apimachineryversion.Info{
registry := NewKubeRegistry(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",
@ -188,7 +179,7 @@ func TestMustRegister(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := newKubeRegistry(&apimachineryversion.Info{
registry := NewKubeRegistry(&apimachineryversion.Info{
Major: "1",
Minor: "15",
GitVersion: "v1.15.0-alpha-1.12345",