Merge pull request #83830 from RainbowMango/pr_introduce_gaugefunc_to_stability_framework

Provide a mechanism for GaugeFunc to use the metrics stability framework
This commit is contained in:
Kubernetes Prow Robot 2019-10-28 21:20:42 -07:00 committed by GitHub
commit d56aaf77b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 0 deletions

View File

@ -48,6 +48,7 @@ go_test(
"//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",
"//vendor/github.com/prometheus/client_golang/prometheus/testutil:go_default_library",
"//vendor/github.com/prometheus/common/expfmt:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],

View File

@ -19,6 +19,8 @@ package metrics
import (
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/component-base/version"
)
// Gauge is our internal representation for our wrapping struct around prometheus
@ -158,3 +160,25 @@ func (v *GaugeVec) Delete(labels map[string]string) bool {
}
return v.GaugeVec.Delete(labels)
}
func newGaugeFunc(opts GaugeOpts, function func() float64, v semver.Version) GaugeFunc {
g := NewGauge(&opts)
if !g.Create(&v) {
return nil
}
return prometheus.NewGaugeFunc(g.GaugeOpts.toPromGaugeOpts(), function)
}
// NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
// value reported is determined by calling the given function from within the
// Write method. Take into account that metric collection may happen
// concurrently. If that results in concurrent calls to Write, like in the case
// where a GaugeFunc is directly registered with Prometheus, the provided
// function must be concurrency-safe.
func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
v := parseVersion(version.Get())
return newGaugeFunc(opts, function, v)
}

View File

@ -17,9 +17,11 @@ limitations under the License.
package metrics
import (
"strings"
"testing"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
apimachineryversion "k8s.io/apimachinery/pkg/version"
@ -191,3 +193,78 @@ func TestGaugeVec(t *testing.T) {
})
}
}
func TestGaugeFunc(t *testing.T) {
currentVersion := apimachineryversion.Info{
Major: "1",
Minor: "17",
GitVersion: "v1.17.0-alpha-1.12345",
}
var function = func() float64 {
return 1
}
var tests = []struct {
desc string
GaugeOpts
expectedMetrics string
}{
{
desc: "Test non deprecated",
GaugeOpts: GaugeOpts{
Namespace: "namespace",
Subsystem: "subsystem",
Name: "metric_non_deprecated",
Help: "gauge help",
},
expectedMetrics: `
# HELP namespace_subsystem_metric_non_deprecated [ALPHA] gauge help
# TYPE namespace_subsystem_metric_non_deprecated gauge
namespace_subsystem_metric_non_deprecated 1
`,
},
{
desc: "Test deprecated",
GaugeOpts: GaugeOpts{
Namespace: "namespace",
Subsystem: "subsystem",
Name: "metric_deprecated",
Help: "gauge help",
DeprecatedVersion: "1.17.0",
},
expectedMetrics: `
# HELP namespace_subsystem_metric_deprecated [ALPHA] (Deprecated since 1.17.0) gauge help
# TYPE namespace_subsystem_metric_deprecated gauge
namespace_subsystem_metric_deprecated 1
`,
},
{
desc: "Test hidden",
GaugeOpts: GaugeOpts{
Namespace: "namespace",
Subsystem: "subsystem",
Name: "metric_hidden",
Help: "gauge help",
DeprecatedVersion: "1.16.0",
},
expectedMetrics: "",
},
}
for _, test := range tests {
tc := test
t.Run(test.desc, func(t *testing.T) {
registry := newKubeRegistry(currentVersion)
gauge := newGaugeFunc(tc.GaugeOpts, function, parseVersion(currentVersion))
if gauge != nil { // hidden metrics will not be initialize, register is not allowed
registry.RawMustRegister(gauge)
}
metricName := BuildFQName(tc.GaugeOpts.Namespace, tc.GaugeOpts.Subsystem, tc.GaugeOpts.Name)
if err := testutil.GatherAndCompare(registry, strings.NewReader(tc.expectedMetrics), metricName); err != nil {
t.Fatal(err)
}
})
}
}

View File

@ -42,6 +42,17 @@ type KubeOpts struct {
StabilityLevel StabilityLevel
}
// BuildFQName joins the given three name components by "_". Empty name
// components are ignored. If the name parameter itself is empty, an empty
// string is returned, no matter what. Metric implementations included in this
// library use this function internally to generate the fully-qualified metric
// name from the name component in their Opts. Users of the library will only
// need this function if they implement their own Metric or instantiate a Desc
// (with NewDesc) directly.
func BuildFQName(namespace, subsystem, name string) string {
return prometheus.BuildFQName(namespace, subsystem, name)
}
// StabilityLevel represents the API guarantees for a given defined metric.
type StabilityLevel string

View File

@ -84,3 +84,12 @@ type PromRegistry interface {
type Gatherer interface {
prometheus.Gatherer
}
// GaugeFunc is a Gauge whose value is determined at collect time by calling a
// provided function.
//
// To create GaugeFunc instances, use NewGaugeFunc.
type GaugeFunc interface {
Metric
Collector
}