add version parsing to metrics framework, use build version information for registry version

This commit is contained in:
Han Kang 2019-04-26 16:43:15 -07:00
parent cebad0da66
commit abe64acc8d
9 changed files with 145 additions and 31 deletions

View File

@ -14,10 +14,13 @@ go_library(
"opts.go",
"registry.go",
"util.go",
"version_parser.go",
"wrappers.go",
],
importpath = "k8s.io/kubernetes/pkg/util/metrics",
deps = [
"//pkg/version:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
@ -32,9 +35,11 @@ go_test(
"counter_test.go",
"registry_test.go",
"util_test.go",
"version_parser_test.go",
],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",

View File

@ -33,13 +33,13 @@ type kubeCounter struct {
// NewCounter returns an object which satisfies the KubeCollector and KubeCounter interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
func NewCounter(opts CounterOpts) *kubeCounter {
func NewCounter(opts *CounterOpts) *kubeCounter {
// todo: handle defaulting better
if opts.StabilityLevel == "" {
opts.StabilityLevel = ALPHA
}
kc := &kubeCounter{
CounterOpts: &opts,
CounterOpts: opts,
lazyMetric: lazyMetric{},
}
kc.setPrometheusCounter(noop)
@ -85,10 +85,10 @@ type kubeCounterVec struct {
// NewCounterVec returns an object which satisfies the KubeCollector and KubeCounterVec interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
func NewCounterVec(opts CounterOpts, labels []string) *kubeCounterVec {
func NewCounterVec(opts *CounterOpts, labels []string) *kubeCounterVec {
cv := &kubeCounterVec{
CounterVec: noopCounterVec,
CounterOpts: &opts,
CounterOpts: opts,
originalLabels: labels,
lazyMetric: lazyMetric{},
}

View File

@ -28,14 +28,14 @@ func TestCounter(t *testing.T) {
v114 := semver.MustParse("1.14.0")
var tests = []struct {
desc string
CounterOpts
*CounterOpts
registryVersion *semver.Version
expectedMetricCount int
expectedHelp string
}{
{
desc: "Test non deprecated",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -48,7 +48,7 @@ func TestCounter(t *testing.T) {
},
{
desc: "Test deprecated",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -62,7 +62,7 @@ func TestCounter(t *testing.T) {
},
{
desc: "Test hidden",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -77,7 +77,7 @@ func TestCounter(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := NewKubeRegistry(*test.registryVersion)
registry := newKubeRegistry(*test.registryVersion)
c := NewCounter(test.CounterOpts)
registry.MustRegister(c)
@ -126,7 +126,7 @@ func TestCounterVec(t *testing.T) {
v114 := semver.MustParse("1.14.0")
var tests = []struct {
desc string
CounterOpts
*CounterOpts
labels []string
registryVersion *semver.Version
expectedMetricFamilyCount int
@ -134,7 +134,7 @@ func TestCounterVec(t *testing.T) {
}{
{
desc: "Test non deprecated",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -147,7 +147,7 @@ func TestCounterVec(t *testing.T) {
},
{
desc: "Test deprecated",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -161,7 +161,7 @@ func TestCounterVec(t *testing.T) {
},
{
desc: "Test hidden",
CounterOpts: CounterOpts{
CounterOpts: &CounterOpts{
Namespace: "namespace",
Name: "metric_test_name",
Subsystem: "subsystem",
@ -177,7 +177,7 @@ func TestCounterVec(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := NewKubeRegistry(*test.registryVersion)
registry := newKubeRegistry(*test.registryVersion)
c := NewCounterVec(test.CounterOpts, test.labels)
registry.MustRegister(c)
c.WithLabelValues("1", "2").Inc()

View File

@ -67,7 +67,7 @@ func (o *CounterOpts) annotateStabilityLevel() {
// convenience function to allow easy transformation to the prometheus
// counterpart. This will do more once we have a proper label abstraction
func (o CounterOpts) toPromCounterOpts() prometheus.CounterOpts {
func (o *CounterOpts) toPromCounterOpts() prometheus.CounterOpts {
return prometheus.CounterOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,

View File

@ -20,12 +20,11 @@ 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"
)
var (
// todo: load the version dynamically at application boot.
DefaultGlobalRegistry = NewKubeRegistry(semver.MustParse("1.15.0"))
)
var DefaultGlobalRegistry = NewKubeRegistry()
type KubeRegistry struct {
PromRegistry
@ -69,9 +68,23 @@ func (kr *KubeRegistry) Gather() ([]*dto.MetricFamily, error) {
return kr.PromRegistry.Gather()
}
// NewRegistry creates a new vanilla Registry without any Collectors
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 %v", *v)
}
return &KubeRegistry{
PromRegistry: prometheus.NewRegistry(),
version: semver.MustParse(*v),
}
}
// newKubeRegistry creates a new vanilla Registry without any Collectors
// pre-registered.
func NewKubeRegistry(version semver.Version) *KubeRegistry {
func newKubeRegistry(version semver.Version) *KubeRegistry {
return &KubeRegistry{
PromRegistry: prometheus.NewRegistry(),
version: version,

View File

@ -27,7 +27,7 @@ var (
v115 = semver.MustParse("1.15.0")
v114 = semver.MustParse("1.14.0")
alphaCounter = NewCounter(
CounterOpts{
&CounterOpts{
Namespace: "some_namespace",
Name: "test_counter_name",
Subsystem: "subsystem",
@ -36,7 +36,7 @@ var (
},
)
alphaDeprecatedCounter = NewCounter(
CounterOpts{
&CounterOpts{
Namespace: "some_namespace",
Name: "test_alpha_dep_counter",
Subsystem: "subsystem",
@ -46,7 +46,7 @@ var (
},
)
alphaHiddenCounter = NewCounter(
CounterOpts{
&CounterOpts{
Namespace: "some_namespace",
Name: "test_alpha_hidden_counter",
Subsystem: "subsystem",
@ -56,7 +56,7 @@ var (
},
)
stableCounter = NewCounter(
CounterOpts{
&CounterOpts{
Namespace: "some_namespace",
Name: "test_some_other_counter",
Subsystem: "subsystem",
@ -116,7 +116,7 @@ func TestRegister(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := NewKubeRegistry(*test.registryVersion)
registry := newKubeRegistry(*test.registryVersion)
for i, m := range test.metrics {
err := registry.Register(m)
if err != test.expectedErrors[i] && err.Error() != test.expectedErrors[i].Error() {
@ -183,7 +183,7 @@ func TestMustRegister(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
registry := NewKubeRegistry(*test.registryVersion)
registry := newKubeRegistry(*test.registryVersion)
for i, m := range test.metrics {
if test.expectedPanics[i] {
assert.Panics(t,

View File

@ -0,0 +1,40 @@
/*
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 metrics
import (
"fmt"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"regexp"
)
const (
versionRegexpString = `^v(\d+\.\d+\.\d+)`
)
var (
versionRe = regexp.MustCompile(versionRegexpString)
)
func parseVersion(ver apimachineryversion.Info) (*string, error) {
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())
}
return &matches[0][1], nil
}

View File

@ -0,0 +1,56 @@
/*
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 metrics
import (
apimachineryversion "k8s.io/apimachinery/pkg/version"
"testing"
)
func TestVersionParsing(t *testing.T) {
var tests = []struct {
desc string
versionString string
expectedVersion string
}{
{
"v1.15.0-alpha-1.12345",
"v1.15.0-alpha-1.12345",
"1.15.0",
},
{
"Parse out defaulted string",
"v0.0.0-master",
"0.0.0",
},
}
for _, test := range tests {
t.Run(test.desc, func(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)
}
})
}
}