...

Source file src/k8s.io/component-base/metrics/histogram.go

Documentation: k8s.io/component-base/metrics

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package metrics
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/blang/semver/v4"
    23  	"github.com/prometheus/client_golang/prometheus"
    24  )
    25  
    26  // Histogram is our internal representation for our wrapping struct around prometheus
    27  // histograms. Summary implements both kubeCollector and ObserverMetric
    28  type Histogram struct {
    29  	ObserverMetric
    30  	*HistogramOpts
    31  	lazyMetric
    32  	selfCollector
    33  }
    34  
    35  // NewHistogram returns an object which is Histogram-like. However, nothing
    36  // will be measured until the histogram is registered somewhere.
    37  func NewHistogram(opts *HistogramOpts) *Histogram {
    38  	opts.StabilityLevel.setDefaults()
    39  
    40  	h := &Histogram{
    41  		HistogramOpts: opts,
    42  		lazyMetric:    lazyMetric{stabilityLevel: opts.StabilityLevel},
    43  	}
    44  	h.setPrometheusHistogram(noopMetric{})
    45  	h.lazyInit(h, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
    46  	return h
    47  }
    48  
    49  // setPrometheusHistogram sets the underlying KubeGauge object, i.e. the thing that does the measurement.
    50  func (h *Histogram) setPrometheusHistogram(histogram prometheus.Histogram) {
    51  	h.ObserverMetric = histogram
    52  	h.initSelfCollection(histogram)
    53  }
    54  
    55  // DeprecatedVersion returns a pointer to the Version or nil
    56  func (h *Histogram) DeprecatedVersion() *semver.Version {
    57  	return parseSemver(h.HistogramOpts.DeprecatedVersion)
    58  }
    59  
    60  // initializeMetric invokes the actual prometheus.Histogram object instantiation
    61  // and stores a reference to it
    62  func (h *Histogram) initializeMetric() {
    63  	h.HistogramOpts.annotateStabilityLevel()
    64  	// this actually creates the underlying prometheus gauge.
    65  	h.setPrometheusHistogram(prometheus.NewHistogram(h.HistogramOpts.toPromHistogramOpts()))
    66  }
    67  
    68  // initializeDeprecatedMetric invokes the actual prometheus.Histogram object instantiation
    69  // but modifies the Help description prior to object instantiation.
    70  func (h *Histogram) initializeDeprecatedMetric() {
    71  	h.HistogramOpts.markDeprecated()
    72  	h.initializeMetric()
    73  }
    74  
    75  // WithContext allows the normal Histogram metric to pass in context. The context is no-op now.
    76  func (h *Histogram) WithContext(ctx context.Context) ObserverMetric {
    77  	return h.ObserverMetric
    78  }
    79  
    80  // HistogramVec is the internal representation of our wrapping struct around prometheus
    81  // histogramVecs.
    82  type HistogramVec struct {
    83  	*prometheus.HistogramVec
    84  	*HistogramOpts
    85  	lazyMetric
    86  	originalLabels []string
    87  }
    88  
    89  // NewHistogramVec returns an object which satisfies kubeCollector and wraps the
    90  // prometheus.HistogramVec object. However, the object returned will not measure
    91  // anything unless the collector is first registered, since the metric is lazily instantiated,
    92  // and only members extracted after
    93  // registration will actually measure anything.
    94  
    95  func NewHistogramVec(opts *HistogramOpts, labels []string) *HistogramVec {
    96  	opts.StabilityLevel.setDefaults()
    97  
    98  	fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
    99  	allowListLock.RLock()
   100  	if allowList, ok := labelValueAllowLists[fqName]; ok {
   101  		opts.LabelValueAllowLists = allowList
   102  	}
   103  	allowListLock.RUnlock()
   104  
   105  	v := &HistogramVec{
   106  		HistogramVec:   noopHistogramVec,
   107  		HistogramOpts:  opts,
   108  		originalLabels: labels,
   109  		lazyMetric:     lazyMetric{stabilityLevel: opts.StabilityLevel},
   110  	}
   111  	v.lazyInit(v, fqName)
   112  	return v
   113  }
   114  
   115  // DeprecatedVersion returns a pointer to the Version or nil
   116  func (v *HistogramVec) DeprecatedVersion() *semver.Version {
   117  	return parseSemver(v.HistogramOpts.DeprecatedVersion)
   118  }
   119  
   120  func (v *HistogramVec) initializeMetric() {
   121  	v.HistogramOpts.annotateStabilityLevel()
   122  	v.HistogramVec = prometheus.NewHistogramVec(v.HistogramOpts.toPromHistogramOpts(), v.originalLabels)
   123  }
   124  
   125  func (v *HistogramVec) initializeDeprecatedMetric() {
   126  	v.HistogramOpts.markDeprecated()
   127  	v.initializeMetric()
   128  }
   129  
   130  // Default Prometheus Vec behavior is that member extraction results in creation of a new element
   131  // if one with the unique label values is not found in the underlying stored metricMap.
   132  // This means  that if this function is called but the underlying metric is not registered
   133  // (which means it will never be exposed externally nor consumed), the metric will exist in memory
   134  // for perpetuity (i.e. throughout application lifecycle).
   135  //
   136  // For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/histogram.go#L460-L470
   137  //
   138  // In contrast, the Vec behavior in this package is that member extraction before registration
   139  // returns a permanent noop object.
   140  
   141  // WithLabelValues returns the ObserverMetric for the given slice of label
   142  // values (same order as the VariableLabels in Desc). If that combination of
   143  // label values is accessed for the first time, a new ObserverMetric is created IFF the HistogramVec
   144  // has been registered to a metrics registry.
   145  func (v *HistogramVec) WithLabelValues(lvs ...string) ObserverMetric {
   146  	if !v.IsCreated() {
   147  		return noop
   148  	}
   149  	if v.LabelValueAllowLists != nil {
   150  		v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
   151  	}
   152  	return v.HistogramVec.WithLabelValues(lvs...)
   153  }
   154  
   155  // With returns the ObserverMetric for the given Labels map (the label names
   156  // must match those of the VariableLabels in Desc). If that label map is
   157  // accessed for the first time, a new ObserverMetric is created IFF the HistogramVec has
   158  // been registered to a metrics registry.
   159  func (v *HistogramVec) With(labels map[string]string) ObserverMetric {
   160  	if !v.IsCreated() {
   161  		return noop
   162  	}
   163  	if v.LabelValueAllowLists != nil {
   164  		v.LabelValueAllowLists.ConstrainLabelMap(labels)
   165  	}
   166  	return v.HistogramVec.With(labels)
   167  }
   168  
   169  // Delete deletes the metric where the variable labels are the same as those
   170  // passed in as labels. It returns true if a metric was deleted.
   171  //
   172  // It is not an error if the number and names of the Labels are inconsistent
   173  // with those of the VariableLabels in Desc. However, such inconsistent Labels
   174  // can never match an actual metric, so the method will always return false in
   175  // that case.
   176  func (v *HistogramVec) Delete(labels map[string]string) bool {
   177  	if !v.IsCreated() {
   178  		return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
   179  	}
   180  	return v.HistogramVec.Delete(labels)
   181  }
   182  
   183  // Reset deletes all metrics in this vector.
   184  func (v *HistogramVec) Reset() {
   185  	if !v.IsCreated() {
   186  		return
   187  	}
   188  
   189  	v.HistogramVec.Reset()
   190  }
   191  
   192  // WithContext returns wrapped HistogramVec with context
   193  func (v *HistogramVec) WithContext(ctx context.Context) *HistogramVecWithContext {
   194  	return &HistogramVecWithContext{
   195  		ctx:          ctx,
   196  		HistogramVec: v,
   197  	}
   198  }
   199  
   200  // HistogramVecWithContext is the wrapper of HistogramVec with context.
   201  type HistogramVecWithContext struct {
   202  	*HistogramVec
   203  	ctx context.Context
   204  }
   205  
   206  // WithLabelValues is the wrapper of HistogramVec.WithLabelValues.
   207  func (vc *HistogramVecWithContext) WithLabelValues(lvs ...string) ObserverMetric {
   208  	return vc.HistogramVec.WithLabelValues(lvs...)
   209  }
   210  
   211  // With is the wrapper of HistogramVec.With.
   212  func (vc *HistogramVecWithContext) With(labels map[string]string) ObserverMetric {
   213  	return vc.HistogramVec.With(labels)
   214  }
   215  

View as plain text