Merge pull request #78877 from logicalhan/global-registry

use noopRegistry for default global legacy prom registry, expose an http handler, introduce registerable interface
This commit is contained in:
Kubernetes Prow Robot 2019-06-17 00:42:08 -07:00 committed by GitHub
commit 5ae55b992b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 86 additions and 49 deletions

View File

@ -22,7 +22,7 @@ import (
) )
// Counter is our internal representation for our wrapping struct around prometheus // 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 { type Counter struct {
CounterMetric CounterMetric
*CounterOpts *CounterOpts
@ -30,7 +30,7 @@ type Counter struct {
selfCollector 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 // However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated. // registered, since the metric is lazily instantiated.
func NewCounter(opts *CounterOpts) *Counter { func NewCounter(opts *CounterOpts) *Counter {
@ -74,7 +74,7 @@ func (c *Counter) initializeDeprecatedMetric() {
} }
// CounterVec is the internal representation of our wrapping struct around prometheus // 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 { type CounterVec struct {
*prometheus.CounterVec *prometheus.CounterVec
*CounterOpts *CounterOpts
@ -82,7 +82,7 @@ type CounterVec struct {
originalLabels []string 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 // However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated. // registered, since the metric is lazily instantiated.
func NewCounterVec(opts *CounterOpts, labels []string) *CounterVec { func NewCounterVec(opts *CounterOpts, labels []string) *CounterVec {

View File

@ -22,7 +22,7 @@ import (
) )
// Gauge is our internal representation for our wrapping struct around prometheus // 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 { type Gauge struct {
GaugeMetric GaugeMetric
*GaugeOpts *GaugeOpts
@ -30,7 +30,7 @@ type Gauge struct {
selfCollector 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 // However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated. // registered, since the metric is lazily instantiated.
func NewGauge(opts *GaugeOpts) *Gauge { func NewGauge(opts *GaugeOpts) *Gauge {
@ -74,7 +74,7 @@ func (g *Gauge) initializeDeprecatedMetric() {
} }
// GaugeVec is the internal representation of our wrapping struct around prometheus // 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 { type GaugeVec struct {
*prometheus.GaugeVec *prometheus.GaugeVec
*GaugeOpts *GaugeOpts
@ -82,7 +82,7 @@ type GaugeVec struct {
originalLabels []string 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 // However, the object returned will not measure anything unless the collector is first
// registered, since the metric is lazily instantiated. // registered, since the metric is lazily instantiated.
func NewGaugeVec(opts *GaugeOpts, labels []string) *GaugeVec { func NewGaugeVec(opts *GaugeOpts, labels []string) *GaugeVec {

View File

@ -23,7 +23,7 @@ import (
) )
// Histogram is our internal representation for our wrapping struct around prometheus // 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 { type Histogram struct {
ObserverMetric ObserverMetric
*HistogramOpts *HistogramOpts
@ -82,7 +82,7 @@ type HistogramVec struct {
originalLabels []string 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 // prometheus.HistogramVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated. // anything unless the collector is first registered, since the metric is lazily instantiated.
func NewHistogramVec(opts *HistogramOpts, labels []string) *HistogramVec { func NewHistogramVec(opts *HistogramOpts, labels []string) *HistogramVec {

View File

@ -11,6 +11,8 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/component-base/metrics: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:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library",
"//vendor/github.com/prometheus/client_model/go:go_default_library",
], ],
) )

View File

@ -18,24 +18,46 @@ package legacyregistry
import ( import (
"fmt" "fmt"
"net/http"
"reflect"
"sync" "sync"
"github.com/prometheus/client_golang/prometheus" "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" apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/component-base/metrics" "k8s.io/component-base/metrics"
) )
var globalRegistryFactory = metricsRegistryFactory{ var (
registerQueue: make([]metrics.KubeCollector, 0), globalRegistryFactory = metricsRegistryFactory{
mustRegisterQueue: make([]metrics.KubeCollector, 0), registerQueue: make([]metrics.Registerable, 0),
} mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
}
)
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 { type metricsRegistryFactory struct {
globalRegistry metrics.KubeRegistry globalRegistry metrics.KubeRegistry
kubeVersion *apimachineryversion.Info kubeVersion *apimachineryversion.Info
registrationLock sync.Mutex registrationLock sync.Mutex
registerQueue []metrics.KubeCollector registerQueue []metrics.Registerable
mustRegisterQueue []metrics.KubeCollector 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 // SetRegistryFactoryVersion sets the kubernetes version information for all
@ -73,29 +95,31 @@ func SetRegistryFactoryVersion(ver apimachineryversion.Info) []error {
// Register registers a collectable metric, but it uses a global registry. Registration is deferred // Register registers a collectable metric, but it uses a global registry. Registration is deferred
// until the global registry has a version to use. // until the global registry has a version to use.
func Register(c metrics.KubeCollector) error { func Register(c metrics.Registerable) error {
globalRegistryFactory.registrationLock.Lock() globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock() defer globalRegistryFactory.registrationLock.Unlock()
if globalRegistryFactory.kubeVersion != nil { if reflect.DeepEqual(globalRegistryFactory.globalRegistry, noopRegistry{}) {
return globalRegistryFactory.globalRegistry.Register(c) 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 // MustRegister works like Register but registers any number of
// Collectors and panics upon the first registration that causes an // Collectors and panics upon the first registration that causes an
// error. Registration is deferred until the global registry has a version to use. // 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() globalRegistryFactory.registrationLock.Lock()
defer globalRegistryFactory.registrationLock.Unlock() defer globalRegistryFactory.registrationLock.Unlock()
if globalRegistryFactory.kubeVersion != nil { if reflect.DeepEqual(globalRegistryFactory.globalRegistry, noopRegistry{}) {
globalRegistryFactory.globalRegistry.MustRegister(cs...) for _, c := range cs {
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c)
}
return return
} }
for _, c := range cs { globalRegistryFactory.globalRegistry.MustRegister(cs...)
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c) return
}
} }

View File

@ -148,8 +148,9 @@ func TestMustRegister(t *testing.T) {
func TestDeferredRegister(t *testing.T) { func TestDeferredRegister(t *testing.T) {
// reset the global registry for this test. // reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{ globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0), registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0), mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
} }
var err error var err error
err = Register(alphaDeprecatedCounter) err = Register(alphaDeprecatedCounter)
@ -177,8 +178,9 @@ func TestDeferredRegister(t *testing.T) {
func TestDeferredMustRegister(t *testing.T) { func TestDeferredMustRegister(t *testing.T) {
// reset the global registry for this test. // reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{ globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0), registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0), mustRegisterQueue: make([]metrics.Registerable, 0),
globalRegistry: noopRegistry{},
} }
MustRegister(alphaDeprecatedCounter) MustRegister(alphaDeprecatedCounter)
@ -197,8 +199,8 @@ func TestDeferredMustRegister(t *testing.T) {
func TestPreloadedMetrics(t *testing.T) { func TestPreloadedMetrics(t *testing.T) {
// reset the global registry for this test. // reset the global registry for this test.
globalRegistryFactory = metricsRegistryFactory{ globalRegistryFactory = metricsRegistryFactory{
registerQueue: make([]metrics.KubeCollector, 0), registerQueue: make([]metrics.Registerable, 0),
mustRegisterQueue: make([]metrics.KubeCollector, 0), mustRegisterQueue: make([]metrics.Registerable, 0),
} }
SetRegistryFactoryVersion(apimachineryversion.Info{ SetRegistryFactoryVersion(apimachineryversion.Info{

View File

@ -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 registration process. Defer metric initialization until Create() is called, which then
delegates to the underlying metric's initializeMetric or initializeDeprecatedMetric delegates to the underlying metric's initializeMetric or initializeDeprecatedMetric
method call depending on whether the metric is deprecated or not. method call depending on whether the metric is deprecated or not.
*/ */
type KubeCollector interface { type kubeCollector interface {
Collector Collector
lazyKubeMetric lazyKubeMetric
DeprecatedVersion() *semver.Version DeprecatedVersion() *semver.Version
@ -57,8 +57,8 @@ type lazyKubeMetric interface {
/* /*
lazyMetric implements lazyKubeMetric. 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 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 implements kubeCollector to get deferred registration behavior. You must call lazyInit
with the KubeCollector itself as an argument. with the kubeCollector itself as an argument.
*/ */
type lazyMetric struct { type lazyMetric struct {
isDeprecated bool isDeprecated bool
@ -66,17 +66,17 @@ type lazyMetric struct {
isCreated bool isCreated bool
markDeprecationOnce sync.Once markDeprecationOnce sync.Once
createOnce sync.Once createOnce sync.Once
self KubeCollector self kubeCollector
} }
func (r *lazyMetric) IsCreated() bool { func (r *lazyMetric) IsCreated() bool {
return r.isCreated 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 // to allow lazy initialization for. It should be invoked in the factory function which creates new
// KubeCollector type objects. // kubeCollector type objects.
func (r *lazyMetric) lazyInit(self KubeCollector) { func (r *lazyMetric) lazyInit(self kubeCollector) {
r.self = self r.self = self
} }

View File

@ -23,12 +23,19 @@ import (
apimachineryversion "k8s.io/apimachinery/pkg/version" 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 // KubeRegistry is an interface which implements a subset of prometheus.Registerer and
// prometheus.Gatherer interfaces // prometheus.Gatherer interfaces
type KubeRegistry interface { type KubeRegistry interface {
Register(KubeCollector) error Register(Registerable) error
MustRegister(...KubeCollector) MustRegister(...Registerable)
Unregister(KubeCollector) bool Unregister(Registerable) bool
Gather() ([]*dto.MetricFamily, error) Gather() ([]*dto.MetricFamily, error)
} }
@ -45,7 +52,7 @@ type kubeRegistry struct {
// Collector are invalid or if they — in combination with descriptors of // Collector are invalid or if they — in combination with descriptors of
// already registered Collectors — do not fulfill the consistency and // already registered Collectors — do not fulfill the consistency and
// uniqueness criteria described in the documentation of metric.Desc. // 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) { if c.Create(&kr.version) {
return kr.PromRegistry.Register(c) return kr.PromRegistry.Register(c)
} }
@ -55,7 +62,7 @@ func (kr *kubeRegistry) Register(c KubeCollector) error {
// MustRegister works like Register but registers any number of // MustRegister works like Register but registers any number of
// Collectors and panics upon the first registration that causes an // Collectors and panics upon the first registration that causes an
// error. // error.
func (kr *kubeRegistry) MustRegister(cs ...KubeCollector) { func (kr *kubeRegistry) MustRegister(cs ...Registerable) {
metrics := make([]prometheus.Collector, 0, len(cs)) metrics := make([]prometheus.Collector, 0, len(cs))
for _, c := range cs { for _, c := range cs {
if c.Create(&kr.version) { if c.Create(&kr.version) {
@ -71,7 +78,7 @@ func (kr *kubeRegistry) MustRegister(cs ...KubeCollector) {
// returns whether a Collector was unregistered. Note that an unchecked // returns whether a Collector was unregistered. Note that an unchecked
// Collector cannot be unregistered (as its Describe method does not // Collector cannot be unregistered (as its Describe method does not
// yield any descriptor). // yield any descriptor).
func (kr *kubeRegistry) Unregister(collector KubeCollector) bool { func (kr *kubeRegistry) Unregister(collector Registerable) bool {
return kr.PromRegistry.Unregister(collector) return kr.PromRegistry.Unregister(collector)
} }

View File

@ -22,7 +22,7 @@ import (
) )
// Summary is our internal representation for our wrapping struct around prometheus // 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 // DEPRECATED: as per the metrics overhaul KEP
type Summary struct { type Summary struct {
@ -87,7 +87,7 @@ type SummaryVec struct {
originalLabels []string 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 // prometheus.SummaryVec object. However, the object returned will not measure
// anything unless the collector is first registered, since the metric is lazily instantiated. // anything unless the collector is first registered, since the metric is lazily instantiated.
// //

View File

@ -59,6 +59,8 @@ type CounterVecMetric interface {
// GaugeMetric is an interface which defines a subset of the interface provided by prometheus.Gauge // GaugeMetric is an interface which defines a subset of the interface provided by prometheus.Gauge
type GaugeMetric interface { type GaugeMetric interface {
Set(float64) Set(float64)
Inc()
Dec()
} }
// ObserverMetric captures individual observations. // ObserverMetric captures individual observations.