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
// counters. Counter implements both KubeCollector and CounterMetric.
// counters. Counter implements both kubeCollector and CounterMetric.
type Counter struct {
CounterMetric
*CounterOpts
@ -30,7 +30,7 @@ type Counter struct {
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 {
@ -74,7 +74,7 @@ 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
@ -82,7 +82,7 @@ type CounterVec struct {
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 {

View File

@ -22,7 +22,7 @@ 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
@ -30,7 +30,7 @@ type Gauge struct {
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 {
@ -74,7 +74,7 @@ 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
@ -82,7 +82,7 @@ type GaugeVec struct {
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 {

View File

@ -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
@ -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 {

View File

@ -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",
],
)

View File

@ -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{},
}
)
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
@ -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
}
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...)
return
}
if reflect.DeepEqual(globalRegistryFactory.globalRegistry, noopRegistry{}) {
for _, c := range cs {
globalRegistryFactory.mustRegisterQueue = append(globalRegistryFactory.mustRegisterQueue, c)
}
return
}
globalRegistryFactory.globalRegistry.MustRegister(cs...)
return
}

View File

@ -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)
@ -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)
@ -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{

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
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
@ -57,8 +57,8 @@ 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
@ -66,17 +66,17 @@ type lazyMetric struct {
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
}

View File

@ -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)
}
@ -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)
}
@ -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) {
@ -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)
}

View File

@ -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 {
@ -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.
//

View File

@ -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.