go.mod: update kubernetes to v1.22.0

This brings in some cri api changes for cgroups, Windows pod sandbox security
context changes and some new fields for the Windows version of a privileged
container.

This also unfortunately bumps the prometheus client, grpc middleware, bolt
and klog :(

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
This commit is contained in:
Daniel Canter
2021-08-06 15:17:34 -07:00
parent 587fc09259
commit e634f04d8c
373 changed files with 44611 additions and 5337 deletions

View File

@@ -0,0 +1,375 @@
/*
Copyright 2016 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 featuregate
import (
"fmt"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/naming"
"k8s.io/klog/v2"
)
type Feature string
const (
flagName = "feature-gates"
// allAlphaGate is a global toggle for alpha features. Per-feature key
// values override the default set by allAlphaGate. Examples:
// AllAlpha=false,NewFeature=true will result in newFeature=true
// AllAlpha=true,NewFeature=false will result in newFeature=false
allAlphaGate Feature = "AllAlpha"
// allBetaGate is a global toggle for beta features. Per-feature key
// values override the default set by allBetaGate. Examples:
// AllBeta=false,NewFeature=true will result in NewFeature=true
// AllBeta=true,NewFeature=false will result in NewFeature=false
allBetaGate Feature = "AllBeta"
)
var (
// The generic features.
defaultFeatures = map[Feature]FeatureSpec{
allAlphaGate: {Default: false, PreRelease: Alpha},
allBetaGate: {Default: false, PreRelease: Beta},
}
// Special handling for a few gates.
specialFeatures = map[Feature]func(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool){
allAlphaGate: setUnsetAlphaGates,
allBetaGate: setUnsetBetaGates,
}
)
type FeatureSpec struct {
// Default is the default enablement state for the feature
Default bool
// LockToDefault indicates that the feature is locked to its default and cannot be changed
LockToDefault bool
// PreRelease indicates the maturity level of the feature
PreRelease prerelease
}
type prerelease string
const (
// Values for PreRelease.
Alpha = prerelease("ALPHA")
Beta = prerelease("BETA")
GA = prerelease("")
// Deprecated
Deprecated = prerelease("DEPRECATED")
)
// FeatureGate indicates whether a given feature is enabled or not
type FeatureGate interface {
// Enabled returns true if the key is enabled.
Enabled(key Feature) bool
// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
KnownFeatures() []string
// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
// set on the copy without mutating the original. This is useful for validating
// config against potential feature gate changes before committing those changes.
DeepCopy() MutableFeatureGate
}
// MutableFeatureGate parses and stores flag gates for known features from
// a string like feature1=true,feature2=false,...
type MutableFeatureGate interface {
FeatureGate
// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
AddFlag(fs *pflag.FlagSet)
// Set parses and stores flag gates for known features
// from a string like feature1=true,feature2=false,...
Set(value string) error
// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
SetFromMap(m map[string]bool) error
// Add adds features to the featureGate.
Add(features map[Feature]FeatureSpec) error
// GetAll returns a copy of the map of known feature names to feature specs.
GetAll() map[Feature]FeatureSpec
}
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
featureGateName string
special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool)
// lock guards writes to known, enabled, and reads/writes of closed
lock sync.Mutex
// known holds a map[Feature]FeatureSpec
known *atomic.Value
// enabled holds a map[Feature]bool
enabled *atomic.Value
// closed is set to true when AddFlag is called, and prevents subsequent calls to Add
closed bool
}
func setUnsetAlphaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
for k, v := range known {
if v.PreRelease == Alpha {
if _, found := enabled[k]; !found {
enabled[k] = val
}
}
}
}
func setUnsetBetaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
for k, v := range known {
if v.PreRelease == Beta {
if _, found := enabled[k]; !found {
enabled[k] = val
}
}
}
}
// Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{}
// internalPackages are packages that ignored when creating a name for featureGates. These packages are in the common
// call chains, so they'd be unhelpful as names.
var internalPackages = []string{"k8s.io/component-base/featuregate/feature_gate.go"}
func NewFeatureGate() *featureGate {
known := map[Feature]FeatureSpec{}
for k, v := range defaultFeatures {
known[k] = v
}
knownValue := &atomic.Value{}
knownValue.Store(known)
enabled := map[Feature]bool{}
enabledValue := &atomic.Value{}
enabledValue.Store(enabled)
f := &featureGate{
featureGateName: naming.GetNameFromCallsite(internalPackages...),
known: knownValue,
special: specialFeatures,
enabled: enabledValue,
}
return f
}
// Set parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
m := make(map[string]bool)
for _, s := range strings.Split(value, ",") {
if len(s) == 0 {
continue
}
arr := strings.SplitN(s, "=", 2)
k := strings.TrimSpace(arr[0])
if len(arr) != 2 {
return fmt.Errorf("missing bool value for %s", k)
}
v := strings.TrimSpace(arr[1])
boolValue, err := strconv.ParseBool(v)
if err != nil {
return fmt.Errorf("invalid value of %s=%s, err: %v", k, v, err)
}
m[k] = boolValue
}
return f.SetFromMap(m)
}
// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
func (f *featureGate) SetFromMap(m map[string]bool) error {
f.lock.Lock()
defer f.lock.Unlock()
// Copy existing state
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
enabled := map[Feature]bool{}
for k, v := range f.enabled.Load().(map[Feature]bool) {
enabled[k] = v
}
for k, v := range m {
k := Feature(k)
featureSpec, ok := known[k]
if !ok {
return fmt.Errorf("unrecognized feature gate: %s", k)
}
if featureSpec.LockToDefault && featureSpec.Default != v {
return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", k, v, featureSpec.Default)
}
enabled[k] = v
// Handle "special" features like "all alpha gates"
if fn, found := f.special[k]; found {
fn(known, enabled, v)
}
if featureSpec.PreRelease == Deprecated {
klog.Warningf("Setting deprecated feature gate %s=%t. It will be removed in a future release.", k, v)
} else if featureSpec.PreRelease == GA {
klog.Warningf("Setting GA feature gate %s=%t. It will be removed in a future release.", k, v)
}
}
// Persist changes
f.known.Store(known)
f.enabled.Store(enabled)
klog.V(1).Infof("feature gates: %v", f.enabled)
return nil
}
// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
pairs := []string{}
for k, v := range f.enabled.Load().(map[Feature]bool) {
pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
}
sort.Strings(pairs)
return strings.Join(pairs, ",")
}
func (f *featureGate) Type() string {
return "mapStringBool"
}
// Add adds features to the featureGate.
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
f.lock.Lock()
defer f.lock.Unlock()
if f.closed {
return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
}
// Copy existing state
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
for name, spec := range features {
if existingSpec, found := known[name]; found {
if existingSpec == spec {
continue
}
return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
}
known[name] = spec
}
// Persist updated state
f.known.Store(known)
return nil
}
// GetAll returns a copy of the map of known feature names to feature specs.
func (f *featureGate) GetAll() map[Feature]FeatureSpec {
retval := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
retval[k] = v
}
return retval
}
// Enabled returns true if the key is enabled. If the key is not known, this call will panic.
func (f *featureGate) Enabled(key Feature) bool {
if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
return v
}
if v, ok := f.known.Load().(map[Feature]FeatureSpec)[key]; ok {
return v.Default
}
panic(fmt.Errorf("feature %q is not registered in FeatureGate %q", key, f.featureGateName))
}
// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
f.lock.Lock()
// TODO(mtaufen): Shouldn't we just close it on the first Set/SetFromMap instead?
// Not all components expose a feature gates flag using this AddFlag method, and
// in the future, all components will completely stop exposing a feature gates flag,
// in favor of componentconfig.
f.closed = true
f.lock.Unlock()
known := f.KnownFeatures()
fs.Var(f, flagName, ""+
"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
"Options are:\n"+strings.Join(known, "\n"))
}
// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
// Deprecated and GA features are hidden from the list.
func (f *featureGate) KnownFeatures() []string {
var known []string
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
if v.PreRelease == GA || v.PreRelease == Deprecated {
continue
}
known = append(known, fmt.Sprintf("%s=true|false (%s - default=%t)", k, v.PreRelease, v.Default))
}
sort.Strings(known)
return known
}
// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
// set on the copy without mutating the original. This is useful for validating
// config against potential feature gate changes before committing those changes.
func (f *featureGate) DeepCopy() MutableFeatureGate {
// Copy existing state.
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
enabled := map[Feature]bool{}
for k, v := range f.enabled.Load().(map[Feature]bool) {
enabled[k] = v
}
// Store copied state in new atomics.
knownValue := &atomic.Value{}
knownValue.Store(known)
enabledValue := &atomic.Value{}
enabledValue.Store(enabled)
// Construct a new featureGate around the copied state.
// Note that specialFeatures is treated as immutable by convention,
// and we maintain the value of f.closed across the copy.
return &featureGate{
special: specialFeatures,
known: knownValue,
enabled: enabledValue,
closed: f.closed,
}
}

11
vendor/k8s.io/component-base/metrics/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,11 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-instrumentation-approvers
- logicalhan
- RainbowMango
reviewers:
- sig-instrumentation-reviewers
- YoyinZyc
labels:
- sig/instrumentation

190
vendor/k8s.io/component-base/metrics/collector.go generated vendored Normal file
View File

@@ -0,0 +1,190 @@
/*
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"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
)
// StableCollector extends the prometheus.Collector interface to allow customization of the
// metric registration process, it's especially intend to be used in scenario of custom collector.
type StableCollector interface {
prometheus.Collector
// DescribeWithStability sends the super-set of all possible metrics.Desc collected
// by this StableCollector to the provided channel.
DescribeWithStability(chan<- *Desc)
// CollectWithStability sends each collected metrics.Metric via the provide channel.
CollectWithStability(chan<- Metric)
// Create will initialize all Desc and it intends to be called by registry.
Create(version *semver.Version, self StableCollector) bool
// ClearState will clear all the states marked by Create.
ClearState()
// HiddenMetrics tells the list of hidden metrics with fqName.
HiddenMetrics() []string
}
// BaseStableCollector which implements almost all of the methods defined by StableCollector
// is a convenient assistant for custom collectors.
// It is recommend that inherit BaseStableCollector when implementing custom collectors.
type BaseStableCollector struct {
descriptors map[string]*Desc // stores all descriptors by pair<fqName, Desc>, these are collected from DescribeWithStability().
registerable map[string]*Desc // stores registerable descriptors by pair<fqName, Desc>, is a subset of descriptors.
hidden map[string]*Desc // stores hidden descriptors by pair<fqName, Desc>, is a subset of descriptors.
self StableCollector
}
// DescribeWithStability sends all descriptors to the provided channel.
// Every custom collector should over-write this method.
func (bsc *BaseStableCollector) DescribeWithStability(ch chan<- *Desc) {
panic(fmt.Errorf("custom collector should over-write DescribeWithStability method"))
}
// Describe sends all descriptors to the provided channel.
// It intend to be called by prometheus registry.
func (bsc *BaseStableCollector) Describe(ch chan<- *prometheus.Desc) {
for _, d := range bsc.registerable {
ch <- d.toPrometheusDesc()
}
}
// CollectWithStability sends all metrics to the provided channel.
// Every custom collector should over-write this method.
func (bsc *BaseStableCollector) CollectWithStability(ch chan<- Metric) {
panic(fmt.Errorf("custom collector should over-write CollectWithStability method"))
}
// Collect is called by the Prometheus registry when collecting metrics.
func (bsc *BaseStableCollector) Collect(ch chan<- prometheus.Metric) {
mch := make(chan Metric)
go func() {
bsc.self.CollectWithStability(mch)
close(mch)
}()
for m := range mch {
// nil Metric usually means hidden metrics
if m == nil {
continue
}
ch <- prometheus.Metric(m)
}
}
func (bsc *BaseStableCollector) add(d *Desc) {
if len(d.fqName) == 0 {
panic("nameless metrics will be not allowed")
}
if bsc.descriptors == nil {
bsc.descriptors = make(map[string]*Desc)
}
if _, exist := bsc.descriptors[d.fqName]; exist {
panic(fmt.Sprintf("duplicate metrics (%s) will be not allowed", d.fqName))
}
bsc.descriptors[d.fqName] = d
}
// Init intends to be called by registry.
func (bsc *BaseStableCollector) init(self StableCollector) {
bsc.self = self
dch := make(chan *Desc)
// collect all possible descriptions from custom side
go func() {
bsc.self.DescribeWithStability(dch)
close(dch)
}()
for d := range dch {
bsc.add(d)
}
}
func (bsc *BaseStableCollector) trackRegistrableDescriptor(d *Desc) {
if bsc.registerable == nil {
bsc.registerable = make(map[string]*Desc)
}
bsc.registerable[d.fqName] = d
}
func (bsc *BaseStableCollector) trackHiddenDescriptor(d *Desc) {
if bsc.hidden == nil {
bsc.hidden = make(map[string]*Desc)
}
bsc.hidden[d.fqName] = d
}
// Create intends to be called by registry.
// Create will return true as long as there is one or more metrics not be hidden.
// Otherwise return false, that means the whole collector will be ignored by registry.
func (bsc *BaseStableCollector) Create(version *semver.Version, self StableCollector) bool {
bsc.init(self)
for _, d := range bsc.descriptors {
d.create(version)
if d.IsHidden() {
bsc.trackHiddenDescriptor(d)
} else {
bsc.trackRegistrableDescriptor(d)
}
}
if len(bsc.registerable) > 0 {
return true
}
return false
}
// ClearState will clear all the states marked by Create.
// It intends to be used for re-register a hidden metric.
func (bsc *BaseStableCollector) ClearState() {
for _, d := range bsc.descriptors {
d.ClearState()
}
bsc.descriptors = nil
bsc.registerable = nil
bsc.hidden = nil
bsc.self = nil
}
// HiddenMetrics tells the list of hidden metrics with fqName.
func (bsc *BaseStableCollector) HiddenMetrics() (fqNames []string) {
for i := range bsc.hidden {
fqNames = append(fqNames, bsc.hidden[i].fqName)
}
return
}
// Check if our BaseStableCollector implements necessary interface
var _ StableCollector = &BaseStableCollector{}

233
vendor/k8s.io/component-base/metrics/counter.go generated vendored Normal file
View File

@@ -0,0 +1,233 @@
/*
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 (
"context"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
// Counter is our internal representation for our wrapping struct around prometheus
// counters. Counter implements both kubeCollector and CounterMetric.
type Counter struct {
CounterMetric
*CounterOpts
lazyMetric
selfCollector
}
// The implementation of the Metric interface is expected by testutil.GetCounterMetricValue.
var _ Metric = &Counter{}
// 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 {
opts.StabilityLevel.setDefaults()
kc := &Counter{
CounterOpts: opts,
lazyMetric: lazyMetric{},
}
kc.setPrometheusCounter(noop)
kc.lazyInit(kc, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
return kc
}
func (c *Counter) Desc() *prometheus.Desc {
return c.metric.Desc()
}
func (c *Counter) Write(to *dto.Metric) error {
return c.metric.Write(to)
}
// Reset resets the underlying prometheus Counter to start counting from 0 again
func (c *Counter) Reset() {
if !c.IsCreated() {
return
}
c.setPrometheusCounter(prometheus.NewCounter(c.CounterOpts.toPromCounterOpts()))
}
// setPrometheusCounter sets the underlying CounterMetric object, i.e. the thing that does the measurement.
func (c *Counter) setPrometheusCounter(counter prometheus.Counter) {
c.CounterMetric = counter
c.initSelfCollection(counter)
}
// DeprecatedVersion returns a pointer to the Version or nil
func (c *Counter) DeprecatedVersion() *semver.Version {
return parseSemver(c.CounterOpts.DeprecatedVersion)
}
// initializeMetric invocation creates the actual underlying Counter. Until this method is called
// the underlying counter is a no-op.
func (c *Counter) initializeMetric() {
c.CounterOpts.annotateStabilityLevel()
// this actually creates the underlying prometheus counter.
c.setPrometheusCounter(prometheus.NewCounter(c.CounterOpts.toPromCounterOpts()))
}
// initializeDeprecatedMetric invocation creates the actual (but deprecated) Counter. Until this method
// is called the underlying counter is a no-op.
func (c *Counter) initializeDeprecatedMetric() {
c.CounterOpts.markDeprecated()
c.initializeMetric()
}
// WithContext allows the normal Counter metric to pass in context. The context is no-op now.
func (c *Counter) WithContext(ctx context.Context) CounterMetric {
return c.CounterMetric
}
// CounterVec is the internal representation of our wrapping struct around prometheus
// 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.
// 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 {
opts.StabilityLevel.setDefaults()
fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
allowListLock.RLock()
if allowList, ok := labelValueAllowLists[fqName]; ok {
opts.LabelValueAllowLists = allowList
}
allowListLock.RUnlock()
cv := &CounterVec{
CounterVec: noopCounterVec,
CounterOpts: opts,
originalLabels: labels,
lazyMetric: lazyMetric{},
}
cv.lazyInit(cv, fqName)
return cv
}
// DeprecatedVersion returns a pointer to the Version or nil
func (v *CounterVec) DeprecatedVersion() *semver.Version {
return parseSemver(v.CounterOpts.DeprecatedVersion)
}
// initializeMetric invocation creates the actual underlying CounterVec. Until this method is called
// the underlying counterVec is a no-op.
func (v *CounterVec) initializeMetric() {
v.CounterOpts.annotateStabilityLevel()
v.CounterVec = prometheus.NewCounterVec(v.CounterOpts.toPromCounterOpts(), v.originalLabels)
}
// initializeDeprecatedMetric invocation creates the actual (but deprecated) CounterVec. Until this method is called
// the underlying counterVec is a no-op.
func (v *CounterVec) initializeDeprecatedMetric() {
v.CounterOpts.markDeprecated()
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/counter.go#L179-L197
// WithLabelValues returns the Counter for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// label values is accessed for the first time, a new Counter is created IFF the counterVec
// has been registered to a metrics registry.
func (v *CounterVec) WithLabelValues(lvs ...string) CounterMetric {
if !v.IsCreated() {
return noop // return no-op counter
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
return v.CounterVec.WithLabelValues(lvs...)
}
// With returns the Counter for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// accessed for the first time, a new Counter is created IFF the counterVec has
// been registered to a metrics registry.
func (v *CounterVec) With(labels map[string]string) CounterMetric {
if !v.IsCreated() {
return noop // return no-op counter
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.CounterVec.With(labels)
}
// Delete deletes the metric where the variable labels are the same as those
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc. However, such inconsistent Labels
// can never match an actual metric, so the method will always return false in
// that case.
func (v *CounterVec) Delete(labels map[string]string) bool {
if !v.IsCreated() {
return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
}
return v.CounterVec.Delete(labels)
}
// Reset deletes all metrics in this vector.
func (v *CounterVec) Reset() {
if !v.IsCreated() {
return
}
v.CounterVec.Reset()
}
// WithContext returns wrapped CounterVec with context
func (v *CounterVec) WithContext(ctx context.Context) *CounterVecWithContext {
return &CounterVecWithContext{
ctx: ctx,
CounterVec: *v,
}
}
// CounterVecWithContext is the wrapper of CounterVec with context.
type CounterVecWithContext struct {
CounterVec
ctx context.Context
}
// WithLabelValues is the wrapper of CounterVec.WithLabelValues.
func (vc *CounterVecWithContext) WithLabelValues(lvs ...string) CounterMetric {
return vc.CounterVec.WithLabelValues(lvs...)
}
// With is the wrapper of CounterVec.With.
func (vc *CounterVecWithContext) With(labels map[string]string) CounterMetric {
return vc.CounterVec.With(labels)
}

225
vendor/k8s.io/component-base/metrics/desc.go generated vendored Normal file
View File

@@ -0,0 +1,225 @@
/*
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"
"sync"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/klog/v2"
)
// Desc is a prometheus.Desc extension.
//
// Use NewDesc to create new Desc instances.
type Desc struct {
// fqName has been built from Namespace, Subsystem, and Name.
fqName string
// help provides some helpful information about this metric.
help string
// constLabels is the label names. Their label values are variable.
constLabels Labels
// variableLabels contains names of labels for which the metric
// maintains variable values.
variableLabels []string
// promDesc is the descriptor used by every Prometheus Metric.
promDesc *prometheus.Desc
annotatedHelp string
// stabilityLevel represents the API guarantees for a given defined metric.
stabilityLevel StabilityLevel
// deprecatedVersion represents in which version this metric be deprecated.
deprecatedVersion string
isDeprecated bool
isHidden bool
isCreated bool
createLock sync.RWMutex
markDeprecationOnce sync.Once
createOnce sync.Once
deprecateOnce sync.Once
hideOnce sync.Once
annotateOnce sync.Once
}
// NewDesc extends prometheus.NewDesc with stability support.
//
// The stabilityLevel should be valid stability label, such as "metrics.ALPHA"
// and "metrics.STABLE"(Maybe "metrics.BETA" in future). Default value "metrics.ALPHA"
// will be used in case of empty or invalid stability label.
//
// The deprecatedVersion represents in which version this Metric be deprecated.
// The deprecation policy outlined by the control plane metrics stability KEP.
func NewDesc(fqName string, help string, variableLabels []string, constLabels Labels,
stabilityLevel StabilityLevel, deprecatedVersion string) *Desc {
d := &Desc{
fqName: fqName,
help: help,
annotatedHelp: help,
variableLabels: variableLabels,
constLabels: constLabels,
stabilityLevel: stabilityLevel,
deprecatedVersion: deprecatedVersion,
}
d.stabilityLevel.setDefaults()
return d
}
// String formats the Desc as a string.
// The stability metadata maybe annotated in 'HELP' section if called after registry,
// otherwise not.
// e.g. "Desc{fqName: "normal_stable_descriptor", help: "[STABLE] this is a stable descriptor", constLabels: {}, variableLabels: []}"
func (d *Desc) String() string {
if d.isCreated {
return d.promDesc.String()
}
return prometheus.NewDesc(d.fqName, d.help, d.variableLabels, prometheus.Labels(d.constLabels)).String()
}
// toPrometheusDesc transform self to prometheus.Desc
func (d *Desc) toPrometheusDesc() *prometheus.Desc {
return d.promDesc
}
// DeprecatedVersion returns a pointer to the Version or nil
func (d *Desc) DeprecatedVersion() *semver.Version {
return parseSemver(d.deprecatedVersion)
}
func (d *Desc) determineDeprecationStatus(version semver.Version) {
selfVersion := d.DeprecatedVersion()
if selfVersion == nil {
return
}
d.markDeprecationOnce.Do(func() {
if selfVersion.LTE(version) {
d.isDeprecated = true
}
if ShouldShowHidden() {
klog.Warningf("Hidden metrics(%s) have been manually overridden, showing this very deprecated metric.", d.fqName)
return
}
if shouldHide(&version, selfVersion) {
// TODO(RainbowMango): Remove this log temporarily. https://github.com/kubernetes/kubernetes/issues/85369
// klog.Warningf("This metric(%s) has been deprecated for more than one release, hiding.", d.fqName)
d.isHidden = true
}
})
}
// IsHidden returns if metric will be hidden
func (d *Desc) IsHidden() bool {
return d.isHidden
}
// IsDeprecated returns if metric has been deprecated
func (d *Desc) IsDeprecated() bool {
return d.isDeprecated
}
// IsCreated returns if metric has been created.
func (d *Desc) IsCreated() bool {
d.createLock.RLock()
defer d.createLock.RUnlock()
return d.isCreated
}
// create forces the initialization of Desc which has been deferred until
// the point at which this method is invoked. This method will determine whether
// the Desc is deprecated or hidden, no-opting if the Desc should be considered
// hidden. Furthermore, this function no-opts and returns true if Desc is already
// created.
func (d *Desc) create(version *semver.Version) bool {
if version != nil {
d.determineDeprecationStatus(*version)
}
// let's not create if this metric is slated to be hidden
if d.IsHidden() {
return false
}
d.createOnce.Do(func() {
d.createLock.Lock()
defer d.createLock.Unlock()
d.isCreated = true
if d.IsDeprecated() {
d.initializeDeprecatedDesc()
} else {
d.initialize()
}
})
return d.IsCreated()
}
// ClearState will clear all the states marked by Create.
// It intends to be used for re-register a hidden metric.
func (d *Desc) ClearState() {
d.isDeprecated = false
d.isHidden = false
d.isCreated = false
d.markDeprecationOnce = *new(sync.Once)
d.createOnce = *new(sync.Once)
d.deprecateOnce = *new(sync.Once)
d.hideOnce = *new(sync.Once)
d.annotateOnce = *new(sync.Once)
d.annotatedHelp = d.help
d.promDesc = nil
}
func (d *Desc) markDeprecated() {
d.deprecateOnce.Do(func() {
d.annotatedHelp = fmt.Sprintf("(Deprecated since %s) %s", d.deprecatedVersion, d.annotatedHelp)
})
}
func (d *Desc) annotateStabilityLevel() {
d.annotateOnce.Do(func() {
d.annotatedHelp = fmt.Sprintf("[%v] %v", d.stabilityLevel, d.annotatedHelp)
})
}
func (d *Desc) initialize() {
d.annotateStabilityLevel()
// this actually creates the underlying prometheus desc.
d.promDesc = prometheus.NewDesc(d.fqName, d.annotatedHelp, d.variableLabels, prometheus.Labels(d.constLabels))
}
func (d *Desc) initializeDeprecatedDesc() {
d.markDeprecated()
d.initialize()
}
// GetRawDesc will returns a new *Desc with original parameters provided to NewDesc().
//
// It will be useful in testing scenario that the same Desc be registered to different registry.
// 1. Desc `D` is registered to registry 'A' in TestA (Note: `D` maybe created)
// 2. Desc `D` is registered to registry 'B' in TestB (Note: since 'D' has been created once, thus will be ignored by registry 'B')
func (d *Desc) GetRawDesc() *Desc {
return NewDesc(d.fqName, d.help, d.variableLabels, d.constLabels, d.stabilityLevel, d.deprecatedVersion)
}

236
vendor/k8s.io/component-base/metrics/gauge.go generated vendored Normal file
View File

@@ -0,0 +1,236 @@
/*
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 (
"context"
"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
// 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.
// 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 {
opts.StabilityLevel.setDefaults()
kc := &Gauge{
GaugeOpts: opts,
lazyMetric: lazyMetric{},
}
kc.setPrometheusGauge(noop)
kc.lazyInit(kc, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
return kc
}
// setPrometheusGauge sets the underlying KubeGauge object, i.e. the thing that does the measurement.
func (g *Gauge) setPrometheusGauge(gauge prometheus.Gauge) {
g.GaugeMetric = gauge
g.initSelfCollection(gauge)
}
// DeprecatedVersion returns a pointer to the Version or nil
func (g *Gauge) DeprecatedVersion() *semver.Version {
return parseSemver(g.GaugeOpts.DeprecatedVersion)
}
// initializeMetric invocation creates the actual underlying Gauge. Until this method is called
// the underlying gauge is a no-op.
func (g *Gauge) initializeMetric() {
g.GaugeOpts.annotateStabilityLevel()
// this actually creates the underlying prometheus gauge.
g.setPrometheusGauge(prometheus.NewGauge(g.GaugeOpts.toPromGaugeOpts()))
}
// initializeDeprecatedMetric invocation creates the actual (but deprecated) Gauge. Until this method
// is called the underlying gauge is a no-op.
func (g *Gauge) initializeDeprecatedMetric() {
g.GaugeOpts.markDeprecated()
g.initializeMetric()
}
// WithContext allows the normal Gauge metric to pass in context. The context is no-op now.
func (g *Gauge) WithContext(ctx context.Context) GaugeMetric {
return g.GaugeMetric
}
// GaugeVec is the internal representation of our wrapping struct around prometheus
// 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.
// 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 {
opts.StabilityLevel.setDefaults()
fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
allowListLock.RLock()
if allowList, ok := labelValueAllowLists[fqName]; ok {
opts.LabelValueAllowLists = allowList
}
allowListLock.RUnlock()
cv := &GaugeVec{
GaugeVec: noopGaugeVec,
GaugeOpts: opts,
originalLabels: labels,
lazyMetric: lazyMetric{},
}
cv.lazyInit(cv, fqName)
return cv
}
// DeprecatedVersion returns a pointer to the Version or nil
func (v *GaugeVec) DeprecatedVersion() *semver.Version {
return parseSemver(v.GaugeOpts.DeprecatedVersion)
}
// initializeMetric invocation creates the actual underlying GaugeVec. Until this method is called
// the underlying gaugeVec is a no-op.
func (v *GaugeVec) initializeMetric() {
v.GaugeOpts.annotateStabilityLevel()
v.GaugeVec = prometheus.NewGaugeVec(v.GaugeOpts.toPromGaugeOpts(), v.originalLabels)
}
// initializeDeprecatedMetric invocation creates the actual (but deprecated) GaugeVec. Until this method is called
// the underlying gaugeVec is a no-op.
func (v *GaugeVec) initializeDeprecatedMetric() {
v.GaugeOpts.markDeprecated()
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/gauge.go#L190-L208
// WithLabelValues returns the GaugeMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// label values is accessed for the first time, a new GaugeMetric is created IFF the gaugeVec
// has been registered to a metrics registry.
func (v *GaugeVec) WithLabelValues(lvs ...string) GaugeMetric {
if !v.IsCreated() {
return noop // return no-op gauge
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
return v.GaugeVec.WithLabelValues(lvs...)
}
// With returns the GaugeMetric for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// accessed for the first time, a new GaugeMetric is created IFF the gaugeVec has
// been registered to a metrics registry.
func (v *GaugeVec) With(labels map[string]string) GaugeMetric {
if !v.IsCreated() {
return noop // return no-op gauge
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.GaugeVec.With(labels)
}
// Delete deletes the metric where the variable labels are the same as those
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc. However, such inconsistent Labels
// can never match an actual metric, so the method will always return false in
// that case.
func (v *GaugeVec) Delete(labels map[string]string) bool {
if !v.IsCreated() {
return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
}
return v.GaugeVec.Delete(labels)
}
// Reset deletes all metrics in this vector.
func (v *GaugeVec) Reset() {
if !v.IsCreated() {
return
}
v.GaugeVec.Reset()
}
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)
}
// WithContext returns wrapped GaugeVec with context
func (v *GaugeVec) WithContext(ctx context.Context) *GaugeVecWithContext {
return &GaugeVecWithContext{
ctx: ctx,
GaugeVec: *v,
}
}
// GaugeVecWithContext is the wrapper of GaugeVec with context.
type GaugeVecWithContext struct {
GaugeVec
ctx context.Context
}
// WithLabelValues is the wrapper of GaugeVec.WithLabelValues.
func (vc *GaugeVecWithContext) WithLabelValues(lvs ...string) GaugeMetric {
return vc.GaugeVec.WithLabelValues(lvs...)
}
// With is the wrapper of GaugeVec.With.
func (vc *GaugeVecWithContext) With(labels map[string]string) GaugeMetric {
return vc.GaugeVec.With(labels)
}

220
vendor/k8s.io/component-base/metrics/histogram.go generated vendored Normal file
View File

@@ -0,0 +1,220 @@
/*
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 (
"context"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
)
// DefBuckets is a wrapper for prometheus.DefBuckets
var DefBuckets = prometheus.DefBuckets
// LinearBuckets is a wrapper for prometheus.LinearBuckets.
func LinearBuckets(start, width float64, count int) []float64 {
return prometheus.LinearBuckets(start, width, count)
}
// ExponentialBuckets is a wrapper for prometheus.ExponentialBuckets.
func ExponentialBuckets(start, factor float64, count int) []float64 {
return prometheus.ExponentialBuckets(start, factor, count)
}
// Histogram is our internal representation for our wrapping struct around prometheus
// histograms. Summary implements both kubeCollector and ObserverMetric
type Histogram struct {
ObserverMetric
*HistogramOpts
lazyMetric
selfCollector
}
// NewHistogram returns an object which is Histogram-like. However, nothing
// will be measured until the histogram is registered somewhere.
func NewHistogram(opts *HistogramOpts) *Histogram {
opts.StabilityLevel.setDefaults()
h := &Histogram{
HistogramOpts: opts,
lazyMetric: lazyMetric{},
}
h.setPrometheusHistogram(noopMetric{})
h.lazyInit(h, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
return h
}
// setPrometheusHistogram sets the underlying KubeGauge object, i.e. the thing that does the measurement.
func (h *Histogram) setPrometheusHistogram(histogram prometheus.Histogram) {
h.ObserverMetric = histogram
h.initSelfCollection(histogram)
}
// DeprecatedVersion returns a pointer to the Version or nil
func (h *Histogram) DeprecatedVersion() *semver.Version {
return parseSemver(h.HistogramOpts.DeprecatedVersion)
}
// initializeMetric invokes the actual prometheus.Histogram object instantiation
// and stores a reference to it
func (h *Histogram) initializeMetric() {
h.HistogramOpts.annotateStabilityLevel()
// this actually creates the underlying prometheus gauge.
h.setPrometheusHistogram(prometheus.NewHistogram(h.HistogramOpts.toPromHistogramOpts()))
}
// initializeDeprecatedMetric invokes the actual prometheus.Histogram object instantiation
// but modifies the Help description prior to object instantiation.
func (h *Histogram) initializeDeprecatedMetric() {
h.HistogramOpts.markDeprecated()
h.initializeMetric()
}
// WithContext allows the normal Histogram metric to pass in context. The context is no-op now.
func (h *Histogram) WithContext(ctx context.Context) ObserverMetric {
return h.ObserverMetric
}
// HistogramVec is the internal representation of our wrapping struct around prometheus
// histogramVecs.
type HistogramVec struct {
*prometheus.HistogramVec
*HistogramOpts
lazyMetric
originalLabels []string
}
// 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 {
opts.StabilityLevel.setDefaults()
fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
allowListLock.RLock()
if allowList, ok := labelValueAllowLists[fqName]; ok {
opts.LabelValueAllowLists = allowList
}
allowListLock.RUnlock()
v := &HistogramVec{
HistogramVec: noopHistogramVec,
HistogramOpts: opts,
originalLabels: labels,
lazyMetric: lazyMetric{},
}
v.lazyInit(v, fqName)
return v
}
// DeprecatedVersion returns a pointer to the Version or nil
func (v *HistogramVec) DeprecatedVersion() *semver.Version {
return parseSemver(v.HistogramOpts.DeprecatedVersion)
}
func (v *HistogramVec) initializeMetric() {
v.HistogramOpts.annotateStabilityLevel()
v.HistogramVec = prometheus.NewHistogramVec(v.HistogramOpts.toPromHistogramOpts(), v.originalLabels)
}
func (v *HistogramVec) initializeDeprecatedMetric() {
v.HistogramOpts.markDeprecated()
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/histogram.go#L460-L470
// WithLabelValues returns the ObserverMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// label values is accessed for the first time, a new ObserverMetric is created IFF the HistogramVec
// has been registered to a metrics registry.
func (v *HistogramVec) WithLabelValues(lvs ...string) ObserverMetric {
if !v.IsCreated() {
return noop
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
return v.HistogramVec.WithLabelValues(lvs...)
}
// With returns the ObserverMetric for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// accessed for the first time, a new ObserverMetric is created IFF the HistogramVec has
// been registered to a metrics registry.
func (v *HistogramVec) With(labels map[string]string) ObserverMetric {
if !v.IsCreated() {
return noop
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.HistogramVec.With(labels)
}
// Delete deletes the metric where the variable labels are the same as those
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc. However, such inconsistent Labels
// can never match an actual metric, so the method will always return false in
// that case.
func (v *HistogramVec) Delete(labels map[string]string) bool {
if !v.IsCreated() {
return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
}
return v.HistogramVec.Delete(labels)
}
// Reset deletes all metrics in this vector.
func (v *HistogramVec) Reset() {
if !v.IsCreated() {
return
}
v.HistogramVec.Reset()
}
// WithContext returns wrapped HistogramVec with context
func (v *HistogramVec) WithContext(ctx context.Context) *HistogramVecWithContext {
return &HistogramVecWithContext{
ctx: ctx,
HistogramVec: *v,
}
}
// HistogramVecWithContext is the wrapper of HistogramVec with context.
type HistogramVecWithContext struct {
HistogramVec
ctx context.Context
}
// WithLabelValues is the wrapper of HistogramVec.WithLabelValues.
func (vc *HistogramVecWithContext) WithLabelValues(lvs ...string) ObserverMetric {
return vc.HistogramVec.WithLabelValues(lvs...)
}
// With is the wrapper of HistogramVec.With.
func (vc *HistogramVecWithContext) With(labels map[string]string) ObserverMetric {
return vc.HistogramVec.With(labels)
}

77
vendor/k8s.io/component-base/metrics/http.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
/*
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 (
"io"
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// These constants cause handlers serving metrics to behave as described if
// errors are encountered.
const (
// Serve an HTTP status code 500 upon the first error
// encountered. Report the error message in the body.
HTTPErrorOnError promhttp.HandlerErrorHandling = iota
// Ignore errors and try to serve as many metrics as possible. However,
// if no metrics can be served, serve an HTTP status code 500 and the
// last error message in the body. Only use this in deliberate "best
// effort" metrics collection scenarios. In this case, it is highly
// recommended to provide other means of detecting errors: By setting an
// ErrorLog in HandlerOpts, the errors are logged. By providing a
// Registry in HandlerOpts, the exposed metrics include an error counter
// "promhttp_metric_handler_errors_total", which can be used for
// alerts.
ContinueOnError
// Panic upon the first error encountered (useful for "crash only" apps).
PanicOnError
)
// HandlerOpts specifies options how to serve metrics via an http.Handler. The
// zero value of HandlerOpts is a reasonable default.
type HandlerOpts promhttp.HandlerOpts
func (ho *HandlerOpts) toPromhttpHandlerOpts() promhttp.HandlerOpts {
return promhttp.HandlerOpts(*ho)
}
// HandlerFor returns an uninstrumented http.Handler for the provided
// Gatherer. The behavior of the Handler is defined by the provided
// HandlerOpts. Thus, HandlerFor is useful to create http.Handlers for custom
// Gatherers, with non-default HandlerOpts, and/or with custom (or no)
// instrumentation. Use the InstrumentMetricHandler function to apply the same
// kind of instrumentation as it is used by the Handler function.
func HandlerFor(reg Gatherer, opts HandlerOpts) http.Handler {
return promhttp.HandlerFor(reg, opts.toPromhttpHandlerOpts())
}
// HandlerWithReset return an http.Handler with Reset
func HandlerWithReset(reg KubeRegistry, opts HandlerOpts) http.Handler {
defaultHandler := promhttp.HandlerFor(reg, opts.toPromhttpHandlerOpts())
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodDelete {
reg.Reset()
io.WriteString(w, "metrics reset\n")
return
}
defaultHandler.ServeHTTP(w, r)
})
}

22
vendor/k8s.io/component-base/metrics/labels.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
/*
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 "github.com/prometheus/client_golang/prometheus"
// Labels represents a collection of label name -> value mappings.
type Labels prometheus.Labels

View File

@@ -0,0 +1,88 @@
/*
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 legacyregistry
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"k8s.io/component-base/metrics"
)
var (
defaultRegistry = metrics.NewKubeRegistry()
// DefaultGatherer exposes the global registry gatherer
DefaultGatherer metrics.Gatherer = defaultRegistry
// Reset calls reset on the global registry
Reset = defaultRegistry.Reset
// MustRegister registers registerable metrics but uses the global registry.
MustRegister = defaultRegistry.MustRegister
// RawMustRegister registers prometheus collectors but uses the global registry, this
// bypasses the metric stability framework
//
// Deprecated
RawMustRegister = defaultRegistry.RawMustRegister
// Register registers a collectable metric but uses the global registry
Register = defaultRegistry.Register
)
func init() {
//lint:ignore SA1019 - replacement function still calls prometheus.NewProcessCollector().
RawMustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
//lint:ignore SA1019 - replacement function still calls prometheus.NewGoCollector().
RawMustRegister(prometheus.NewGoCollector())
}
// Handler returns an HTTP handler for the DefaultGatherer. It is
// already instrumented with InstrumentHandler (using "prometheus" as handler
// name).
//
// Deprecated: Please note the issues described in the doc comment of
// InstrumentHandler. You might want to consider using promhttp.Handler instead.
func Handler() http.Handler {
return promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, promhttp.HandlerFor(defaultRegistry, promhttp.HandlerOpts{}))
}
// HandlerWithReset returns an HTTP handler for the DefaultGatherer but invokes
// registry reset if the http method is DELETE.
func HandlerWithReset() http.Handler {
return promhttp.InstrumentMetricHandler(
prometheus.DefaultRegisterer,
metrics.HandlerWithReset(defaultRegistry, metrics.HandlerOpts{}))
}
// CustomRegister registers a custom collector but uses the global registry.
func CustomRegister(c metrics.StableCollector) error {
err := defaultRegistry.CustomRegister(c)
//TODO(RainbowMango): Maybe we can wrap this error by error wrapping.(Golang 1.13)
_ = prometheus.Register(c)
return err
}
// CustomMustRegister registers custom collectors but uses the global registry.
func CustomMustRegister(cs ...metrics.StableCollector) {
defaultRegistry.CustomMustRegister(cs...)
for _, c := range cs {
prometheus.MustRegister(c)
}
}

243
vendor/k8s.io/component-base/metrics/metric.go generated vendored Normal file
View File

@@ -0,0 +1,243 @@
/*
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 (
"sync"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"k8s.io/klog/v2"
)
/*
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 {
Collector
lazyKubeMetric
DeprecatedVersion() *semver.Version
// Each collector metric should provide an initialization function
// for both deprecated and non-deprecated variants of a metric. This
// is necessary since metric instantiation will be deferred
// until the metric is actually registered somewhere.
initializeMetric()
initializeDeprecatedMetric()
}
/*
lazyKubeMetric defines our metric registration interface. lazyKubeMetric objects are expected
to lazily instantiate metrics (i.e defer metric instantiation until when
the Create() function is explicitly called).
*/
type lazyKubeMetric interface {
Create(*semver.Version) bool
IsCreated() bool
IsHidden() bool
IsDeprecated() bool
}
/*
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.
*/
type lazyMetric struct {
fqName string
isDeprecated bool
isHidden bool
isCreated bool
createLock sync.RWMutex
markDeprecationOnce sync.Once
createOnce sync.Once
self kubeCollector
}
func (r *lazyMetric) IsCreated() bool {
r.createLock.RLock()
defer r.createLock.RUnlock()
return r.isCreated
}
// 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, fqName string) {
r.fqName = fqName
r.self = self
}
// preprocessMetric figures out whether the lazy metric should be hidden or not.
// This method takes a Version argument which should be the version of the binary in which
// this code is currently being executed. A metric can be hidden under two conditions:
// 1. if the metric is deprecated and is outside the grace period (i.e. has been
// deprecated for more than one release
// 2. if the metric is manually disabled via a CLI flag.
//
// Disclaimer: disabling a metric via a CLI flag has higher precedence than
// deprecation and will override show-hidden-metrics for the explicitly
// disabled metric.
func (r *lazyMetric) preprocessMetric(version semver.Version) {
disabledMetricsLock.RLock()
defer disabledMetricsLock.RUnlock()
// disabling metrics is higher in precedence than showing hidden metrics
if _, ok := disabledMetrics[r.fqName]; ok {
r.isHidden = true
return
}
selfVersion := r.self.DeprecatedVersion()
if selfVersion == nil {
return
}
r.markDeprecationOnce.Do(func() {
if selfVersion.LTE(version) {
r.isDeprecated = true
}
if ShouldShowHidden() {
klog.Warningf("Hidden metrics (%s) have been manually overridden, showing this very deprecated metric.", r.fqName)
return
}
if shouldHide(&version, selfVersion) {
// TODO(RainbowMango): Remove this log temporarily. https://github.com/kubernetes/kubernetes/issues/85369
// klog.Warningf("This metric has been deprecated for more than one release, hiding.")
r.isHidden = true
}
})
}
func (r *lazyMetric) IsHidden() bool {
return r.isHidden
}
func (r *lazyMetric) IsDeprecated() bool {
return r.isDeprecated
}
// Create forces the initialization of metric which has been deferred until
// the point at which this method is invoked. This method will determine whether
// the metric is deprecated or hidden, no-opting if the metric should be considered
// hidden. Furthermore, this function no-opts and returns true if metric is already
// created.
func (r *lazyMetric) Create(version *semver.Version) bool {
if version != nil {
r.preprocessMetric(*version)
}
// let's not create if this metric is slated to be hidden
if r.IsHidden() {
return false
}
r.createOnce.Do(func() {
r.createLock.Lock()
defer r.createLock.Unlock()
r.isCreated = true
if r.IsDeprecated() {
r.self.initializeDeprecatedMetric()
} else {
r.self.initializeMetric()
}
})
return r.IsCreated()
}
// ClearState will clear all the states marked by Create.
// It intends to be used for re-register a hidden metric.
func (r *lazyMetric) ClearState() {
r.createLock.Lock()
defer r.createLock.Unlock()
r.isDeprecated = false
r.isHidden = false
r.isCreated = false
r.markDeprecationOnce = *(new(sync.Once))
r.createOnce = *(new(sync.Once))
}
// FQName returns the fully-qualified metric name of the collector.
func (r *lazyMetric) FQName() string {
return r.fqName
}
/*
This code is directly lifted from the prometheus codebase. It's a convenience struct which
allows you satisfy the Collector interface automatically if you already satisfy the Metric interface.
For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/collector.go#L98-L120
*/
type selfCollector struct {
metric prometheus.Metric
}
func (c *selfCollector) initSelfCollection(m prometheus.Metric) {
c.metric = m
}
func (c *selfCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.metric.Desc()
}
func (c *selfCollector) Collect(ch chan<- prometheus.Metric) {
ch <- c.metric
}
// no-op vecs for convenience
var noopCounterVec = &prometheus.CounterVec{}
var noopHistogramVec = &prometheus.HistogramVec{}
var noopGaugeVec = &prometheus.GaugeVec{}
var noopObserverVec = &noopObserverVector{}
// just use a convenience struct for all the no-ops
var noop = &noopMetric{}
type noopMetric struct{}
func (noopMetric) Inc() {}
func (noopMetric) Add(float64) {}
func (noopMetric) Dec() {}
func (noopMetric) Set(float64) {}
func (noopMetric) Sub(float64) {}
func (noopMetric) Observe(float64) {}
func (noopMetric) SetToCurrentTime() {}
func (noopMetric) Desc() *prometheus.Desc { return nil }
func (noopMetric) Write(*dto.Metric) error { return nil }
func (noopMetric) Describe(chan<- *prometheus.Desc) {}
func (noopMetric) Collect(chan<- prometheus.Metric) {}
type noopObserverVector struct{}
func (noopObserverVector) GetMetricWith(prometheus.Labels) (prometheus.Observer, error) {
return noop, nil
}
func (noopObserverVector) GetMetricWithLabelValues(...string) (prometheus.Observer, error) {
return noop, nil
}
func (noopObserverVector) With(prometheus.Labels) prometheus.Observer { return noop }
func (noopObserverVector) WithLabelValues(...string) prometheus.Observer { return noop }
func (noopObserverVector) CurryWith(prometheus.Labels) (prometheus.ObserverVec, error) {
return noopObserverVec, nil
}
func (noopObserverVector) MustCurryWith(prometheus.Labels) prometheus.ObserverVec {
return noopObserverVec
}
func (noopObserverVector) Describe(chan<- *prometheus.Desc) {}
func (noopObserverVector) Collect(chan<- prometheus.Metric) {}

125
vendor/k8s.io/component-base/metrics/options.go generated vendored Normal file
View File

@@ -0,0 +1,125 @@
/*
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"
"regexp"
"github.com/blang/semver"
"github.com/spf13/pflag"
"k8s.io/component-base/version"
)
// Options has all parameters needed for exposing metrics from components
type Options struct {
ShowHiddenMetricsForVersion string
DisabledMetrics []string
AllowListMapping map[string]string
}
// NewOptions returns default metrics options
func NewOptions() *Options {
return &Options{}
}
// Validate validates metrics flags options.
func (o *Options) Validate() []error {
var errs []error
err := validateShowHiddenMetricsVersion(parseVersion(version.Get()), o.ShowHiddenMetricsForVersion)
if err != nil {
errs = append(errs, err)
}
if err := validateAllowMetricLabel(o.AllowListMapping); err != nil {
errs = append(errs, err)
}
if len(errs) == 0 {
return nil
}
return errs
}
// AddFlags adds flags for exposing component metrics.
func (o *Options) AddFlags(fs *pflag.FlagSet) {
if o != nil {
o = NewOptions()
}
fs.StringVar(&o.ShowHiddenMetricsForVersion, "show-hidden-metrics-for-version", o.ShowHiddenMetricsForVersion,
"The previous version for which you want to show hidden metrics. "+
"Only the previous minor version is meaningful, other values will not be allowed. "+
"The format is <major>.<minor>, e.g.: '1.16'. "+
"The purpose of this format is make sure you have the opportunity to notice if the next release hides additional metrics, "+
"rather than being surprised when they are permanently removed in the release after that.")
fs.StringSliceVar(&o.DisabledMetrics,
"disabled-metrics",
o.DisabledMetrics,
"This flag provides an escape hatch for misbehaving metrics. "+
"You must provide the fully qualified metric name in order to disable it. "+
"Disclaimer: disabling metrics is higher in precedence than showing hidden metrics.")
fs.StringToStringVar(&o.AllowListMapping, "allow-metric-labels", o.AllowListMapping,
"The map from metric-label to value allow-list of this label. The key's format is <MetricName>,<LabelName>. "+
"The value's format is <allowed_value>,<allowed_value>..."+
"e.g. metric1,label1='v1,v2,v3', metric1,label2='v1,v2,v3' metric2,label1='v1,v2,v3'.")
}
// Apply applies parameters into global configuration of metrics.
func (o *Options) Apply() {
if o == nil {
return
}
if len(o.ShowHiddenMetricsForVersion) > 0 {
SetShowHidden()
}
// set disabled metrics
for _, metricName := range o.DisabledMetrics {
SetDisabledMetric(metricName)
}
if o.AllowListMapping != nil {
SetLabelAllowListFromCLI(o.AllowListMapping)
}
}
func validateShowHiddenMetricsVersion(currentVersion semver.Version, targetVersionStr string) error {
if targetVersionStr == "" {
return nil
}
validVersionStr := fmt.Sprintf("%d.%d", currentVersion.Major, currentVersion.Minor-1)
if targetVersionStr != validVersionStr {
return fmt.Errorf("--show-hidden-metrics-for-version must be omitted or have the value '%v'. Only the previous minor version is allowed", validVersionStr)
}
return nil
}
func validateAllowMetricLabel(allowListMapping map[string]string) error {
if allowListMapping == nil {
return nil
}
metricNameRegex := `[a-zA-Z_:][a-zA-Z0-9_:]*`
labelRegex := `[a-zA-Z_][a-zA-Z0-9_]*`
for k := range allowListMapping {
reg := regexp.MustCompile(metricNameRegex + `,` + labelRegex)
if reg.FindString(k) != k {
return fmt.Errorf("--allow-metric-labels must has a list of kv pair with format `metricName:labelName=labelValue, labelValue,...`")
}
}
return nil
}

301
vendor/k8s.io/component-base/metrics/opts.go generated vendored Normal file
View File

@@ -0,0 +1,301 @@
/*
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"
"strings"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/util/sets"
)
var (
labelValueAllowLists = map[string]*MetricLabelAllowList{}
allowListLock sync.RWMutex
)
// KubeOpts is superset struct for prometheus.Opts. The prometheus Opts structure
// is purposefully not embedded here because that would change struct initialization
// in the manner which people are currently accustomed.
//
// Name must be set to a non-empty string. DeprecatedVersion is defined only
// if the metric for which this options applies is, in fact, deprecated.
type KubeOpts struct {
Namespace string
Subsystem string
Name string
Help string
ConstLabels map[string]string
DeprecatedVersion string
deprecateOnce sync.Once
annotateOnce sync.Once
StabilityLevel StabilityLevel
LabelValueAllowLists *MetricLabelAllowList
}
// 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
const (
// ALPHA metrics have no stability guarantees, as such, labels may
// be arbitrarily added/removed and the metric may be deleted at any time.
ALPHA StabilityLevel = "ALPHA"
// STABLE metrics are guaranteed not be mutated and removal is governed by
// the deprecation policy outlined in by the control plane metrics stability KEP.
STABLE StabilityLevel = "STABLE"
)
// setDefaults takes 'ALPHA' in case of empty.
func (sl *StabilityLevel) setDefaults() {
switch *sl {
case "":
*sl = ALPHA
default:
// no-op, since we have a StabilityLevel already
}
}
// CounterOpts is an alias for Opts. See there for doc comments.
type CounterOpts KubeOpts
// Modify help description on the metric description.
func (o *CounterOpts) markDeprecated() {
o.deprecateOnce.Do(func() {
o.Help = fmt.Sprintf("(Deprecated since %v) %v", o.DeprecatedVersion, o.Help)
})
}
// annotateStabilityLevel annotates help description on the metric description with the stability level
// of the metric
func (o *CounterOpts) annotateStabilityLevel() {
o.annotateOnce.Do(func() {
o.Help = fmt.Sprintf("[%v] %v", o.StabilityLevel, o.Help)
})
}
// 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 {
return prometheus.CounterOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,
Name: o.Name,
Help: o.Help,
ConstLabels: o.ConstLabels,
}
}
// GaugeOpts is an alias for Opts. See there for doc comments.
type GaugeOpts KubeOpts
// Modify help description on the metric description.
func (o *GaugeOpts) markDeprecated() {
o.deprecateOnce.Do(func() {
o.Help = fmt.Sprintf("(Deprecated since %v) %v", o.DeprecatedVersion, o.Help)
})
}
// annotateStabilityLevel annotates help description on the metric description with the stability level
// of the metric
func (o *GaugeOpts) annotateStabilityLevel() {
o.annotateOnce.Do(func() {
o.Help = fmt.Sprintf("[%v] %v", o.StabilityLevel, o.Help)
})
}
// convenience function to allow easy transformation to the prometheus
// counterpart. This will do more once we have a proper label abstraction
func (o *GaugeOpts) toPromGaugeOpts() prometheus.GaugeOpts {
return prometheus.GaugeOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,
Name: o.Name,
Help: o.Help,
ConstLabels: o.ConstLabels,
}
}
// HistogramOpts bundles the options for creating a Histogram metric. It is
// mandatory to set Name to a non-empty string. All other fields are optional
// and can safely be left at their zero value, although it is strongly
// encouraged to set a Help string.
type HistogramOpts struct {
Namespace string
Subsystem string
Name string
Help string
ConstLabels map[string]string
Buckets []float64
DeprecatedVersion string
deprecateOnce sync.Once
annotateOnce sync.Once
StabilityLevel StabilityLevel
LabelValueAllowLists *MetricLabelAllowList
}
// Modify help description on the metric description.
func (o *HistogramOpts) markDeprecated() {
o.deprecateOnce.Do(func() {
o.Help = fmt.Sprintf("(Deprecated since %v) %v", o.DeprecatedVersion, o.Help)
})
}
// annotateStabilityLevel annotates help description on the metric description with the stability level
// of the metric
func (o *HistogramOpts) annotateStabilityLevel() {
o.annotateOnce.Do(func() {
o.Help = fmt.Sprintf("[%v] %v", o.StabilityLevel, o.Help)
})
}
// convenience function to allow easy transformation to the prometheus
// counterpart. This will do more once we have a proper label abstraction
func (o *HistogramOpts) toPromHistogramOpts() prometheus.HistogramOpts {
return prometheus.HistogramOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,
Name: o.Name,
Help: o.Help,
ConstLabels: o.ConstLabels,
Buckets: o.Buckets,
}
}
// SummaryOpts bundles the options for creating a Summary metric. It is
// mandatory to set Name to a non-empty string. While all other fields are
// optional and can safely be left at their zero value, it is recommended to set
// a help string and to explicitly set the Objectives field to the desired value
// as the default value will change in the upcoming v0.10 of the library.
type SummaryOpts struct {
Namespace string
Subsystem string
Name string
Help string
ConstLabels map[string]string
Objectives map[float64]float64
MaxAge time.Duration
AgeBuckets uint32
BufCap uint32
DeprecatedVersion string
deprecateOnce sync.Once
annotateOnce sync.Once
StabilityLevel StabilityLevel
LabelValueAllowLists *MetricLabelAllowList
}
// Modify help description on the metric description.
func (o *SummaryOpts) markDeprecated() {
o.deprecateOnce.Do(func() {
o.Help = fmt.Sprintf("(Deprecated since %v) %v", o.DeprecatedVersion, o.Help)
})
}
// annotateStabilityLevel annotates help description on the metric description with the stability level
// of the metric
func (o *SummaryOpts) annotateStabilityLevel() {
o.annotateOnce.Do(func() {
o.Help = fmt.Sprintf("[%v] %v", o.StabilityLevel, o.Help)
})
}
// Deprecated: DefObjectives will not be used as the default objectives in
// v1.0.0 of the library. The default Summary will have no quantiles then.
var (
defObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
)
// convenience function to allow easy transformation to the prometheus
// counterpart. This will do more once we have a proper label abstraction
func (o *SummaryOpts) toPromSummaryOpts() prometheus.SummaryOpts {
// we need to retain existing quantile behavior for backwards compatibility,
// so let's do what prometheus used to do prior to v1.
objectives := o.Objectives
if objectives == nil {
objectives = defObjectives
}
return prometheus.SummaryOpts{
Namespace: o.Namespace,
Subsystem: o.Subsystem,
Name: o.Name,
Help: o.Help,
ConstLabels: o.ConstLabels,
Objectives: objectives,
MaxAge: o.MaxAge,
AgeBuckets: o.AgeBuckets,
BufCap: o.BufCap,
}
}
type MetricLabelAllowList struct {
labelToAllowList map[string]sets.String
}
func (allowList *MetricLabelAllowList) ConstrainToAllowedList(labelNameList, labelValueList []string) {
for index, value := range labelValueList {
name := labelNameList[index]
if allowValues, ok := allowList.labelToAllowList[name]; ok {
if !allowValues.Has(value) {
labelValueList[index] = "unexpected"
}
}
}
}
func (allowList *MetricLabelAllowList) ConstrainLabelMap(labels map[string]string) {
for name, value := range labels {
if allowValues, ok := allowList.labelToAllowList[name]; ok {
if !allowValues.Has(value) {
labels[name] = "unexpected"
}
}
}
}
func SetLabelAllowListFromCLI(allowListMapping map[string]string) {
allowListLock.Lock()
defer allowListLock.Unlock()
for metricLabelName, labelValues := range allowListMapping {
metricName := strings.Split(metricLabelName, ",")[0]
labelName := strings.Split(metricLabelName, ",")[1]
valueSet := sets.NewString(strings.Split(labelValues, ",")...)
allowList, ok := labelValueAllowLists[metricName]
if ok {
allowList.labelToAllowList[labelName] = valueSet
} else {
labelToAllowList := make(map[string]sets.String)
labelToAllowList[labelName] = valueSet
labelValueAllowLists[metricName] = &MetricLabelAllowList{
labelToAllowList,
}
}
}
}

View File

@@ -0,0 +1,51 @@
/*
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 (
"time"
"k8s.io/klog/v2"
)
var processStartTime = NewGaugeVec(
&GaugeOpts{
Name: "process_start_time_seconds",
Help: "Start time of the process since unix epoch in seconds.",
StabilityLevel: ALPHA,
},
[]string{},
)
// RegisterProcessStartTime registers the process_start_time_seconds to
// a prometheus registry. This metric needs to be included to ensure counter
// data fidelity.
func RegisterProcessStartTime(registrationFunc func(Registerable) error) error {
start, err := getProcessStart()
if err != nil {
klog.Errorf("Could not get process start time, %v", err)
start = float64(time.Now().Unix())
}
// processStartTime is a lazy metric which only get initialized after registered.
// so we need to register the metric first and then set the value for it
if err = registrationFunc(processStartTime); err != nil {
return err
}
processStartTime.WithLabelValues().Set(start)
return nil
}

View File

@@ -0,0 +1,38 @@
// +build !windows
/*
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 (
"os"
"github.com/prometheus/procfs"
)
func getProcessStart() (float64, error) {
pid := os.Getpid()
p, err := procfs.NewProc(pid)
if err != nil {
return 0, err
}
if stat, err := p.Stat(); err == nil {
return stat.StartTime()
}
return 0, err
}

View File

@@ -0,0 +1,33 @@
// +build windows
/*
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 (
"golang.org/x/sys/windows"
)
func getProcessStart() (float64, error) {
processHandle := windows.CurrentProcess()
var creationTime, exitTime, kernelTime, userTime windows.Filetime
if err := windows.GetProcessTimes(processHandle, &creationTime, &exitTime, &kernelTime, &userTime); err != nil {
return 0, err
}
return float64(creationTime.Nanoseconds() / 1e9), nil
}

337
vendor/k8s.io/component-base/metrics/registry.go generated vendored Normal file
View File

@@ -0,0 +1,337 @@
/*
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"
"sync"
"sync/atomic"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/component-base/version"
)
var (
showHiddenOnce sync.Once
disabledMetricsLock sync.RWMutex
showHidden atomic.Value
registries []*kubeRegistry // stores all registries created by NewKubeRegistry()
registriesLock sync.RWMutex
disabledMetrics = map[string]struct{}{}
)
// shouldHide be used to check if a specific metric with deprecated version should be hidden
// according to metrics deprecation lifecycle.
func shouldHide(currentVersion *semver.Version, deprecatedVersion *semver.Version) bool {
guardVersion, err := semver.Make(fmt.Sprintf("%d.%d.0", currentVersion.Major, currentVersion.Minor))
if err != nil {
panic("failed to make version from current version")
}
if deprecatedVersion.LT(guardVersion) {
return true
}
return false
}
// ValidateShowHiddenMetricsVersion checks invalid version for which show hidden metrics.
func ValidateShowHiddenMetricsVersion(v string) []error {
err := validateShowHiddenMetricsVersion(parseVersion(version.Get()), v)
if err != nil {
return []error{err}
}
return nil
}
func SetDisabledMetric(name string) {
disabledMetricsLock.Lock()
defer disabledMetricsLock.Unlock()
disabledMetrics[name] = struct{}{}
}
// SetShowHidden will enable showing hidden metrics. This will no-opt
// after the initial call
func SetShowHidden() {
showHiddenOnce.Do(func() {
showHidden.Store(true)
// re-register collectors that has been hidden in phase of last registry.
for _, r := range registries {
r.enableHiddenCollectors()
r.enableHiddenStableCollectors()
}
})
}
// ShouldShowHidden returns whether showing hidden deprecated metrics
// is enabled. While the primary usecase for this is internal (to determine
// registration behavior) this can also be used to introspect
func ShouldShowHidden() bool {
return showHidden.Load() != nil && showHidden.Load().(bool)
}
// Registerable is an interface for a collector metric which we
// will register with KubeRegistry.
type Registerable interface {
prometheus.Collector
// Create will mark deprecated state for the collector
Create(version *semver.Version) bool
// ClearState will clear all the states marked by Create.
ClearState()
// FQName returns the fully-qualified metric name of the collector.
FQName() string
}
type resettable interface {
Reset()
}
// KubeRegistry is an interface which implements a subset of prometheus.Registerer and
// prometheus.Gatherer interfaces
type KubeRegistry interface {
// Deprecated
RawMustRegister(...prometheus.Collector)
// CustomRegister is our internal variant of Prometheus registry.Register
CustomRegister(c StableCollector) error
// CustomMustRegister is our internal variant of Prometheus registry.MustRegister
CustomMustRegister(cs ...StableCollector)
// Register conforms to Prometheus registry.Register
Register(Registerable) error
// MustRegister conforms to Prometheus registry.MustRegister
MustRegister(...Registerable)
// Unregister conforms to Prometheus registry.Unregister
Unregister(collector Collector) bool
// Gather conforms to Prometheus gatherer.Gather
Gather() ([]*dto.MetricFamily, error)
// Reset invokes the Reset() function on all items in the registry
// which are added as resettables.
Reset()
}
// kubeRegistry is a wrapper around a prometheus registry-type object. Upon initialization
// the kubernetes binary version information is loaded into the registry object, so that
// automatic behavior can be configured for metric versioning.
type kubeRegistry struct {
PromRegistry
version semver.Version
hiddenCollectors map[string]Registerable // stores all collectors that has been hidden
stableCollectors []StableCollector // stores all stable collector
hiddenCollectorsLock sync.RWMutex
stableCollectorsLock sync.RWMutex
resetLock sync.RWMutex
resettables []resettable
}
// Register registers a new Collector to be included in metrics
// collection. It returns an error if the descriptors provided by the
// 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 Registerable) error {
if c.Create(&kr.version) {
defer kr.addResettable(c)
return kr.PromRegistry.Register(c)
}
kr.trackHiddenCollector(c)
return nil
}
// 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 ...Registerable) {
metrics := make([]prometheus.Collector, 0, len(cs))
for _, c := range cs {
if c.Create(&kr.version) {
metrics = append(metrics, c)
kr.addResettable(c)
} else {
kr.trackHiddenCollector(c)
}
}
kr.PromRegistry.MustRegister(metrics...)
}
// CustomRegister registers a new custom collector.
func (kr *kubeRegistry) CustomRegister(c StableCollector) error {
kr.trackStableCollectors(c)
defer kr.addResettable(c)
if c.Create(&kr.version, c) {
return kr.PromRegistry.Register(c)
}
return nil
}
// CustomMustRegister works like CustomRegister but registers any number of
// StableCollectors and panics upon the first registration that causes an
// error.
func (kr *kubeRegistry) CustomMustRegister(cs ...StableCollector) {
kr.trackStableCollectors(cs...)
collectors := make([]prometheus.Collector, 0, len(cs))
for _, c := range cs {
if c.Create(&kr.version, c) {
kr.addResettable(c)
collectors = append(collectors, c)
}
}
kr.PromRegistry.MustRegister(collectors...)
}
// RawMustRegister takes a native prometheus.Collector and registers the collector
// to the registry. This bypasses metrics safety checks, so should only be used
// to register custom prometheus collectors.
//
// Deprecated
func (kr *kubeRegistry) RawMustRegister(cs ...prometheus.Collector) {
kr.PromRegistry.MustRegister(cs...)
for _, c := range cs {
kr.addResettable(c)
}
}
// addResettable will automatically add our metric to our reset
// list if it satisfies the interface
func (kr *kubeRegistry) addResettable(i interface{}) {
kr.resetLock.Lock()
defer kr.resetLock.Unlock()
if resettable, ok := i.(resettable); ok {
kr.resettables = append(kr.resettables, resettable)
}
}
// Unregister unregisters the Collector that equals the Collector passed
// in as an argument. (Two Collectors are considered equal if their
// Describe method yields the same set of descriptors.) The function
// 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 Collector) bool {
return kr.PromRegistry.Unregister(collector)
}
// Gather calls the Collect method of the registered Collectors and then
// gathers the collected metrics into a lexicographically sorted slice
// of uniquely named MetricFamily protobufs. Gather ensures that the
// returned slice is valid and self-consistent so that it can be used
// for valid exposition. As an exception to the strict consistency
// requirements described for metric.Desc, Gather will tolerate
// different sets of label names for metrics of the same metric family.
func (kr *kubeRegistry) Gather() ([]*dto.MetricFamily, error) {
return kr.PromRegistry.Gather()
}
// trackHiddenCollector stores all hidden collectors.
func (kr *kubeRegistry) trackHiddenCollector(c Registerable) {
kr.hiddenCollectorsLock.Lock()
defer kr.hiddenCollectorsLock.Unlock()
kr.hiddenCollectors[c.FQName()] = c
}
// trackStableCollectors stores all custom collectors.
func (kr *kubeRegistry) trackStableCollectors(cs ...StableCollector) {
kr.stableCollectorsLock.Lock()
defer kr.stableCollectorsLock.Unlock()
kr.stableCollectors = append(kr.stableCollectors, cs...)
}
// enableHiddenCollectors will re-register all of the hidden collectors.
func (kr *kubeRegistry) enableHiddenCollectors() {
if len(kr.hiddenCollectors) == 0 {
return
}
kr.hiddenCollectorsLock.Lock()
cs := make([]Registerable, 0, len(kr.hiddenCollectors))
for _, c := range kr.hiddenCollectors {
c.ClearState()
cs = append(cs, c)
}
kr.hiddenCollectors = nil
kr.hiddenCollectorsLock.Unlock()
kr.MustRegister(cs...)
}
// enableHiddenStableCollectors will re-register the stable collectors if there is one or more hidden metrics in it.
// Since we can not register a metrics twice, so we have to unregister first then register again.
func (kr *kubeRegistry) enableHiddenStableCollectors() {
if len(kr.stableCollectors) == 0 {
return
}
kr.stableCollectorsLock.Lock()
cs := make([]StableCollector, 0, len(kr.stableCollectors))
for _, c := range kr.stableCollectors {
if len(c.HiddenMetrics()) > 0 {
kr.Unregister(c) // unregister must happens before clear state, otherwise no metrics would be unregister
c.ClearState()
cs = append(cs, c)
}
}
kr.stableCollectors = nil
kr.stableCollectorsLock.Unlock()
kr.CustomMustRegister(cs...)
}
// Reset invokes Reset on all metrics that are resettable.
func (kr *kubeRegistry) Reset() {
kr.resetLock.RLock()
defer kr.resetLock.RUnlock()
for _, r := range kr.resettables {
r.Reset()
}
}
// BuildVersion is a helper function that can be easily mocked.
var BuildVersion = version.Get
func newKubeRegistry(v apimachineryversion.Info) *kubeRegistry {
r := &kubeRegistry{
PromRegistry: prometheus.NewRegistry(),
version: parseVersion(v),
hiddenCollectors: make(map[string]Registerable),
resettables: make([]resettable, 0),
}
registriesLock.Lock()
defer registriesLock.Unlock()
registries = append(registries, r)
return r
}
// NewKubeRegistry creates a new vanilla Registry without any Collectors
// pre-registered.
func NewKubeRegistry() KubeRegistry {
r := newKubeRegistry(BuildVersion())
return r
}

214
vendor/k8s.io/component-base/metrics/summary.go generated vendored Normal file
View File

@@ -0,0 +1,214 @@
/*
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 (
"context"
"github.com/blang/semver"
"github.com/prometheus/client_golang/prometheus"
)
// Summary is our internal representation for our wrapping struct around prometheus
// summaries. Summary implements both kubeCollector and ObserverMetric
//
// DEPRECATED: as per the metrics overhaul KEP
type Summary struct {
ObserverMetric
*SummaryOpts
lazyMetric
selfCollector
}
// NewSummary returns an object which is Summary-like. However, nothing
// will be measured until the summary is registered somewhere.
//
// DEPRECATED: as per the metrics overhaul KEP
func NewSummary(opts *SummaryOpts) *Summary {
opts.StabilityLevel.setDefaults()
s := &Summary{
SummaryOpts: opts,
lazyMetric: lazyMetric{},
}
s.setPrometheusSummary(noopMetric{})
s.lazyInit(s, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
return s
}
// setPrometheusSummary sets the underlying KubeGauge object, i.e. the thing that does the measurement.
func (s *Summary) setPrometheusSummary(summary prometheus.Summary) {
s.ObserverMetric = summary
s.initSelfCollection(summary)
}
// DeprecatedVersion returns a pointer to the Version or nil
func (s *Summary) DeprecatedVersion() *semver.Version {
return parseSemver(s.SummaryOpts.DeprecatedVersion)
}
// initializeMetric invokes the actual prometheus.Summary object instantiation
// and stores a reference to it
func (s *Summary) initializeMetric() {
s.SummaryOpts.annotateStabilityLevel()
// this actually creates the underlying prometheus gauge.
s.setPrometheusSummary(prometheus.NewSummary(s.SummaryOpts.toPromSummaryOpts()))
}
// initializeDeprecatedMetric invokes the actual prometheus.Summary object instantiation
// but modifies the Help description prior to object instantiation.
func (s *Summary) initializeDeprecatedMetric() {
s.SummaryOpts.markDeprecated()
s.initializeMetric()
}
// WithContext allows the normal Summary metric to pass in context. The context is no-op now.
func (s *Summary) WithContext(ctx context.Context) ObserverMetric {
return s.ObserverMetric
}
// SummaryVec is the internal representation of our wrapping struct around prometheus
// summaryVecs.
//
// DEPRECATED: as per the metrics overhaul KEP
type SummaryVec struct {
*prometheus.SummaryVec
*SummaryOpts
lazyMetric
originalLabels []string
}
// 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.
//
// DEPRECATED: as per the metrics overhaul KEP
func NewSummaryVec(opts *SummaryOpts, labels []string) *SummaryVec {
opts.StabilityLevel.setDefaults()
fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
allowListLock.RLock()
if allowList, ok := labelValueAllowLists[fqName]; ok {
opts.LabelValueAllowLists = allowList
}
allowListLock.RUnlock()
v := &SummaryVec{
SummaryOpts: opts,
originalLabels: labels,
lazyMetric: lazyMetric{},
}
v.lazyInit(v, fqName)
return v
}
// DeprecatedVersion returns a pointer to the Version or nil
func (v *SummaryVec) DeprecatedVersion() *semver.Version {
return parseSemver(v.SummaryOpts.DeprecatedVersion)
}
func (v *SummaryVec) initializeMetric() {
v.SummaryOpts.annotateStabilityLevel()
v.SummaryVec = prometheus.NewSummaryVec(v.SummaryOpts.toPromSummaryOpts(), v.originalLabels)
}
func (v *SummaryVec) initializeDeprecatedMetric() {
v.SummaryOpts.markDeprecated()
v.initializeMetric()
}
// Default Prometheus behavior actually results in the creation of a new metric
// if a metric with the unique label values is not found in the underlying stored metricMap.
// This means that if this function is called but the underlying metric is not registered
// (which means it will never be exposed externally nor consumed), the metric will exist in memory
// for perpetuity (i.e. throughout application lifecycle).
//
// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/summary.go#L485-L495
// WithLabelValues returns the ObserverMetric for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// label values is accessed for the first time, a new ObserverMetric is created IFF the summaryVec
// has been registered to a metrics registry.
func (v *SummaryVec) WithLabelValues(lvs ...string) ObserverMetric {
if !v.IsCreated() {
return noop
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
}
return v.SummaryVec.WithLabelValues(lvs...)
}
// With returns the ObserverMetric for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// accessed for the first time, a new ObserverMetric is created IFF the summaryVec has
// been registered to a metrics registry.
func (v *SummaryVec) With(labels map[string]string) ObserverMetric {
if !v.IsCreated() {
return noop
}
if v.LabelValueAllowLists != nil {
v.LabelValueAllowLists.ConstrainLabelMap(labels)
}
return v.SummaryVec.With(labels)
}
// Delete deletes the metric where the variable labels are the same as those
// passed in as labels. It returns true if a metric was deleted.
//
// It is not an error if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc. However, such inconsistent Labels
// can never match an actual metric, so the method will always return false in
// that case.
func (v *SummaryVec) Delete(labels map[string]string) bool {
if !v.IsCreated() {
return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
}
return v.SummaryVec.Delete(labels)
}
// Reset deletes all metrics in this vector.
func (v *SummaryVec) Reset() {
if !v.IsCreated() {
return
}
v.SummaryVec.Reset()
}
// WithContext returns wrapped SummaryVec with context
func (v *SummaryVec) WithContext(ctx context.Context) *SummaryVecWithContext {
return &SummaryVecWithContext{
ctx: ctx,
SummaryVec: *v,
}
}
// SummaryVecWithContext is the wrapper of SummaryVec with context.
type SummaryVecWithContext struct {
SummaryVec
ctx context.Context
}
// WithLabelValues is the wrapper of SummaryVec.WithLabelValues.
func (vc *SummaryVecWithContext) WithLabelValues(lvs ...string) ObserverMetric {
return vc.SummaryVec.WithLabelValues(lvs...)
}
// With is the wrapper of SummaryVec.With.
func (vc *SummaryVecWithContext) With(labels map[string]string) ObserverMetric {
return vc.SummaryVec.With(labels)
}

60
vendor/k8s.io/component-base/metrics/value.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
/*
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 (
"time"
"github.com/prometheus/client_golang/prometheus"
)
// ValueType is an enumeration of metric types that represent a simple value.
type ValueType int
// Possible values for the ValueType enum.
const (
_ ValueType = iota
CounterValue
GaugeValue
UntypedValue
)
func (vt *ValueType) toPromValueType() prometheus.ValueType {
return prometheus.ValueType(*vt)
}
// NewLazyConstMetric is a helper of MustNewConstMetric.
//
// Note: If the metrics described by the desc is hidden, the metrics will not be created.
func NewLazyConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
if desc.IsHidden() {
return nil
}
return prometheus.MustNewConstMetric(desc.toPrometheusDesc(), valueType.toPromValueType(), value, labelValues...)
}
// NewLazyMetricWithTimestamp is a helper of NewMetricWithTimestamp.
//
// Warning: the Metric 'm' must be the one created by NewLazyConstMetric(),
// otherwise, no stability guarantees would be offered.
func NewLazyMetricWithTimestamp(t time.Time, m Metric) Metric {
if m == nil {
return nil
}
return prometheus.NewMetricWithTimestamp(t, m)
}

37
vendor/k8s.io/component-base/metrics/version.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
/*
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 "k8s.io/component-base/version"
var (
buildInfo = NewGaugeVec(
&GaugeOpts{
Name: "kubernetes_build_info",
Help: "A metric with a constant '1' value labeled by major, minor, git version, git commit, git tree state, build date, Go version, and compiler from which Kubernetes was built, and platform on which it is running.",
StabilityLevel: ALPHA,
},
[]string{"major", "minor", "git_version", "git_commit", "git_tree_state", "build_date", "go_version", "compiler", "platform"},
)
)
// RegisterBuildInfo registers the build and version info in a metadata metric in prometheus
func RegisterBuildInfo(r KubeRegistry) {
info := version.Get()
r.MustRegister(buildInfo)
buildInfo.WithLabelValues(info.Major, info.Minor, info.GitVersion, info.GitCommit, info.GitTreeState, info.BuildDate, info.GoVersion, info.Compiler, info.Platform).Set(1)
}

50
vendor/k8s.io/component-base/metrics/version_parser.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
/*
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"
"regexp"
"github.com/blang/semver"
apimachineryversion "k8s.io/apimachinery/pkg/version"
)
const (
versionRegexpString = `^v(\d+\.\d+\.\d+)`
)
var (
versionRe = regexp.MustCompile(versionRegexpString)
)
func parseSemver(s string) *semver.Version {
if s != "" {
sv := semver.MustParse(s)
return &sv
}
return nil
}
func parseVersion(ver apimachineryversion.Info) semver.Version {
matches := versionRe.FindAllStringSubmatch(ver.String(), -1)
if len(matches) != 1 {
panic(fmt.Sprintf("version string \"%v\" doesn't match expected regular expression: \"%v\"", ver.String(), versionRe.String()))
}
return semver.MustParse(matches[0][1])
}

95
vendor/k8s.io/component-base/metrics/wrappers.go generated vendored Normal file
View File

@@ -0,0 +1,95 @@
/*
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 (
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
// This file contains a series of interfaces which we explicitly define for
// integrating with prometheus. We redefine the interfaces explicitly here
// so that we can prevent breakage if methods are ever added to prometheus
// variants of them.
// Collector defines a subset of prometheus.Collector interface methods
type Collector interface {
Describe(chan<- *prometheus.Desc)
Collect(chan<- prometheus.Metric)
}
// Metric defines a subset of prometheus.Metric interface methods
type Metric interface {
Desc() *prometheus.Desc
Write(*dto.Metric) error
}
// CounterMetric is a Metric that represents a single numerical value that only ever
// goes up. That implies that it cannot be used to count items whose number can
// also go down, e.g. the number of currently running goroutines. Those
// "counters" are represented by Gauges.
// CounterMetric is an interface which defines a subset of the interface provided by prometheus.Counter
type CounterMetric interface {
Inc()
Add(float64)
}
// CounterVecMetric is an interface which prometheus.CounterVec satisfies.
type CounterVecMetric interface {
WithLabelValues(...string) CounterMetric
With(prometheus.Labels) CounterMetric
}
// GaugeMetric is an interface which defines a subset of the interface provided by prometheus.Gauge
type GaugeMetric interface {
Set(float64)
Inc()
Dec()
Add(float64)
Write(out *dto.Metric) error
SetToCurrentTime()
}
// ObserverMetric captures individual observations.
type ObserverMetric interface {
Observe(float64)
}
// PromRegistry is an interface which implements a subset of prometheus.Registerer and
// prometheus.Gatherer interfaces
type PromRegistry interface {
Register(prometheus.Collector) error
MustRegister(...prometheus.Collector)
Unregister(prometheus.Collector) bool
Gather() ([]*dto.MetricFamily, error)
}
// Gatherer is the interface for the part of a registry in charge of gathering
// the collected metrics into a number of MetricFamilies.
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
}

1
vendor/k8s.io/component-base/version/.gitattributes generated vendored Normal file
View File

@@ -0,0 +1 @@
base.go export-subst

63
vendor/k8s.io/component-base/version/base.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
/*
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 version
// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// If you are looking at these fields in the git tree, they look
// strange. They are modified on the fly by the build process. The
// in-tree values are dummy values used for "git archive", which also
// works for GitHub tar downloads.
//
// When releasing a new Kubernetes version, this file is updated by
// build/mark_new_version.sh to reflect the new version, and then a
// git annotated tag (using format vX.Y where X == Major version and Y
// == Minor version) is created to point to the commit that updates
// component-base/version/base.go
var (
// TODO: Deprecate gitMajor and gitMinor, use only gitVersion
// instead. First step in deprecation, keep the fields but make
// them irrelevant. (Next we'll take it out, which may muck with
// scripts consuming the kubectl version output - but most of
// these should be looking at gitVersion already anyways.)
gitMajor string // major version, always numeric
gitMinor string // minor version, numeric possibly followed by "+"
// semantic version, derived by build scripts (see
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/release/versioning.md
// for a detailed discussion of this field)
//
// TODO: This field is still called "gitVersion" for legacy
// reasons. For prerelease versions, the build metadata on the
// semantic version is a git hash, but the version itself is no
// longer the direct output of "git describe", but a slight
// translation to be semver compliant.
// NOTE: The $Format strings are replaced during 'git archive' thanks to the
// companion .gitattributes file containing 'export-subst' in this same
// directory. See also https://git-scm.com/docs/gitattributes
gitVersion = "v0.0.0-master+$Format:%H$"
gitCommit = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
gitTreeState = "" // state of git tree, either "clean" or "dirty"
buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)

42
vendor/k8s.io/component-base/version/version.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
/*
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 version
import (
"fmt"
"runtime"
apimachineryversion "k8s.io/apimachinery/pkg/version"
)
// Get returns the overall codebase version. It's for detecting
// what code a binary was built from.
func Get() apimachineryversion.Info {
// These variables typically come from -ldflags settings and in
// their absence fallback to the settings in ./base.go
return apimachineryversion.Info{
Major: gitMajor,
Minor: gitMinor,
GitVersion: gitVersion,
GitCommit: gitCommit,
GitTreeState: gitTreeState,
BuildDate: buildDate,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
}