Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use noopRegistry for default global legacy prom registry, expose an http handler, introduce registerable interface #78877

Merged
merged 3 commits into from
Jun 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions staging/src/k8s.io/component-base/metrics/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ import (
)

// Counter is our internal representation for our wrapping struct around prometheus
// counters. Counter implements both KubeCollector and CounterMetric.
// counters. Counter implements both kubeCollector and CounterMetric.
type Counter struct {
CounterMetric
*CounterOpts
lazyMetric
selfCollector
}

// NewCounter returns an object which satisfies the KubeCollector and CounterMetric interfaces.
// NewCounter returns an object which satisfies the kubeCollector and CounterMetric 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) *Counter {
Expand Down Expand Up @@ -74,15 +74,15 @@ func (c *Counter) initializeDeprecatedMetric() {
}

// CounterVec is the internal representation of our wrapping struct around prometheus
// counterVecs. CounterVec implements both KubeCollector and CounterVecMetric.
// counterVecs. CounterVec implements both kubeCollector and CounterVecMetric.
type CounterVec struct {
*prometheus.CounterVec
*CounterOpts
lazyMetric
originalLabels []string
}

// NewCounterVec returns an object which satisfies the KubeCollector and CounterVecMetric interfaces.
// NewCounterVec returns an object which satisfies the kubeCollector and CounterVecMetric 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) *CounterVec {
Expand Down
8 changes: 4 additions & 4 deletions staging/src/k8s.io/component-base/metrics/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ import (
)

// Gauge is our internal representation for our wrapping struct around prometheus
// gauges. kubeGauge implements both KubeCollector and KubeGauge.
// gauges. kubeGauge implements both kubeCollector and KubeGauge.
type Gauge struct {
GaugeMetric
*GaugeOpts
lazyMetric
selfCollector
}

// NewGauge returns an object which satisfies the KubeCollector and KubeGauge interfaces.
// NewGauge returns an object which satisfies the kubeCollector and KubeGauge interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
func NewGauge(opts *GaugeOpts) *Gauge {
Expand Down Expand Up @@ -74,15 +74,15 @@ func (g *Gauge) initializeDeprecatedMetric() {
}

// GaugeVec is the internal representation of our wrapping struct around prometheus
// gaugeVecs. kubeGaugeVec implements both KubeCollector and KubeGaugeVec.
// gaugeVecs. kubeGaugeVec implements both kubeCollector and KubeGaugeVec.
type GaugeVec struct {
*prometheus.GaugeVec
*GaugeOpts
lazyMetric
originalLabels []string
}

// NewGaugeVec returns an object which satisfies the KubeCollector and KubeGaugeVec interfaces.
// NewGaugeVec returns an object which satisfies the kubeCollector and KubeGaugeVec interfaces.
// However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated.
func NewGaugeVec(opts *GaugeOpts, labels []string) *GaugeVec {
Expand Down
4 changes: 2 additions & 2 deletions staging/src/k8s.io/component-base/metrics/histogram.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

// Histogram is our internal representation for our wrapping struct around prometheus
// histograms. Summary implements both KubeCollector and ObserverMetric
// histograms. Summary implements both kubeCollector and ObserverMetric
type Histogram struct {
ObserverMetric
*HistogramOpts
Expand Down Expand Up @@ -82,7 +82,7 @@ type HistogramVec struct {
originalLabels []string
}

// NewHistogramVec returns an object which satisfies KubeCollector and wraps the
// NewHistogramVec returns an object which satisfies kubeCollector and wraps the
// prometheus.HistogramVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated.
func NewHistogramVec(opts *HistogramOpts, labels []string) *HistogramVec {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ go_library(
"//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_golang/prometheus:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library",
"//vendor/github.com/prometheus/client_model/go:go_default_library",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,46 @@ package legacyregistry

import (
"fmt"
"net/http"
"reflect"
"sync"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
dto "github.com/prometheus/client_model/go"

apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/component-base/metrics"
)

var globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
}
var (
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I don't really get why we need such noopRegistry here.
And I prefer not to preset globalRegistryFactory with noopRegistry, since functions like SetRegistryFactoryVersion will make changes to globalRegistryFactory as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer the explicitness of overriding a default noop registry. Otherwise, the behavior is dependent on implications of having a global registry version registered.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also more consistent with other usages in Kubernetes:

.

}
)

type noopRegistry struct{}

func (noopRegistry) Register(metrics.Registerable) error { return nil }
func (noopRegistry) MustRegister(...metrics.Registerable) {}
func (noopRegistry) Unregister(metrics.Registerable) bool { return true }
func (noopRegistry) Gather() ([]*dto.MetricFamily, error) { return nil, nil }

type metricsRegistryFactory struct {
globalRegistry metrics.KubeRegistry
kubeVersion *apimachineryversion.Info
registrationLock sync.Mutex
registerQueue []metrics.KubeCollector
mustRegisterQueue []metrics.KubeCollector
registerQueue []metrics.Registerable
mustRegisterQueue []metrics.Registerable
}

// HandlerForGlobalRegistry returns a http handler for the global registry. This
// allows us to return a handler for the global registry without having to expose
// the global registry itself directly.
func HandlerForGlobalRegistry(opts promhttp.HandlerOpts) http.Handler {
return promhttp.HandlerFor(globalRegistryFactory.globalRegistry, opts)
}

// SetRegistryFactoryVersion sets the kubernetes version information for all
Expand Down Expand Up @@ -73,29 +95,31 @@ func SetRegistryFactoryVersion(ver apimachineryversion.Info) []error {

// 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 {
func Register(c metrics.Registerable) error {
globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock()

if globalRegistryFactory.kubeVersion != nil {
return globalRegistryFactory.globalRegistry.Register(c)
if reflect.DeepEqual(globalRegistryFactory.globalRegistry, noopRegistry{}) {
globalRegistryFactory.registerQueue = append(globalRegistryFactory.registerQueue, c)
return nil
}
globalRegistryFactory.registerQueue = append(globalRegistryFactory.registerQueue, c)
return nil

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. Registration is deferred until the global registry has a version to use.
func MustRegister(cs ...metrics.KubeCollector) {
func MustRegister(cs ...metrics.Registerable) {
globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock()

if globalRegistryFactory.kubeVersion != nil {
globalRegistryFactory.globalRegistry.MustRegister(cs...)
if reflect.DeepEqual(globalRegistryFactory.globalRegistry, noopRegistry{}) {
for _, c := range cs {
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c)
}
return
}
for _, c := range cs {
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c)
}
globalRegistryFactory.globalRegistry.MustRegister(cs...)
return
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ func TestMustRegister(t *testing.T) {
func TestDeferredRegister(t *testing.T) {
// reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
}
var err error
err = Register(alphaDeprecatedCounter)
Expand Down Expand Up @@ -177,8 +178,9 @@ func TestDeferredRegister(t *testing.T) {
func TestDeferredMustRegister(t *testing.T) {
// reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
}
MustRegister(alphaDeprecatedCounter)

Expand All @@ -197,8 +199,8 @@ func TestDeferredMustRegister(t *testing.T) {
func TestPreloadedMetrics(t *testing.T) {
// reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0),
registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.Registerable, 0),
}

SetRegistryFactoryVersion(apimachineryversion.Info{
Expand Down
16 changes: 8 additions & 8 deletions staging/src/k8s.io/component-base/metrics/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import (
)

/*
KubeCollector extends the prometheus.Collector interface to allow customization of the metric
kubeCollector extends the prometheus.Collector interface to allow customization of the metric
registration process. Defer metric initialization until Create() is called, which then
delegates to the underlying metric's initializeMetric or initializeDeprecatedMetric
method call depending on whether the metric is deprecated or not.
*/
type KubeCollector interface {
type kubeCollector interface {
Collector
lazyKubeMetric
DeprecatedVersion() *semver.Version
Expand All @@ -57,26 +57,26 @@ type lazyKubeMetric interface {
/*
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.
implements kubeCollector to get deferred registration behavior. You must call lazyInit
with the kubeCollector itself as an argument.
*/
type lazyMetric struct {
isDeprecated bool
isHidden bool
isCreated bool
markDeprecationOnce sync.Once
createOnce sync.Once
self KubeCollector
self kubeCollector
}

func (r *lazyMetric) IsCreated() bool {
return r.isCreated
}

// lazyInit provides the lazyMetric with a reference to the KubeCollector it is supposed
// lazyInit provides the lazyMetric with a reference to the kubeCollector it is supposed
// to allow lazy initialization for. It should be invoked in the factory function which creates new
// KubeCollector type objects.
func (r *lazyMetric) lazyInit(self KubeCollector) {
// kubeCollector type objects.
func (r *lazyMetric) lazyInit(self kubeCollector) {
r.self = self
}

Expand Down
19 changes: 13 additions & 6 deletions staging/src/k8s.io/component-base/metrics/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ import (
apimachineryversion "k8s.io/apimachinery/pkg/version"
)

// Registerable is an interface for a collector metric which we
// will register with KubeRegistry.
type Registerable interface {
prometheus.Collector
Create(version *semver.Version) bool
}

// 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
Register(Registerable) error
MustRegister(...Registerable)
Unregister(Registerable) bool
Gather() ([]*dto.MetricFamily, error)
}

Expand All @@ -45,7 +52,7 @@ type kubeRegistry struct {
// 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 Registerable) error {
if c.Create(&kr.version) {
return kr.PromRegistry.Register(c)
}
Expand All @@ -55,7 +62,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 ...Registerable) {
metrics := make([]prometheus.Collector, 0, len(cs))
for _, c := range cs {
if c.Create(&kr.version) {
Expand All @@ -71,7 +78,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 Registerable) bool {
return kr.PromRegistry.Unregister(collector)
}

Expand Down
4 changes: 2 additions & 2 deletions staging/src/k8s.io/component-base/metrics/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

// Summary is our internal representation for our wrapping struct around prometheus
// summaries. Summary implements both KubeCollector and ObserverMetric
// summaries. Summary implements both kubeCollector and ObserverMetric
//
// DEPRECATED: as per the metrics overhaul KEP
type Summary struct {
Expand Down Expand Up @@ -87,7 +87,7 @@ type SummaryVec struct {
originalLabels []string
}

// NewSummaryVec returns an object which satisfies KubeCollector and wraps the
// NewSummaryVec returns an object which satisfies kubeCollector and wraps the
// prometheus.SummaryVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated.
//
Expand Down
2 changes: 2 additions & 0 deletions staging/src/k8s.io/component-base/metrics/wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type CounterVecMetric interface {
// GaugeMetric is an interface which defines a subset of the interface provided by prometheus.Gauge
type GaugeMetric interface {
Set(float64)
Inc()
Dec()
}

// ObserverMetric captures individual observations.
Expand Down