...

Source file src/k8s.io/component-base/metrics/timing_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  	"time"
    22  
    23  	"github.com/blang/semver/v4"
    24  	promext "k8s.io/component-base/metrics/prometheusextension"
    25  )
    26  
    27  // PrometheusTimingHistogram is the abstraction of the underlying histogram
    28  // that we want to promote from the wrapper.
    29  type PrometheusTimingHistogram interface {
    30  	GaugeMetric
    31  }
    32  
    33  // TimingHistogram is our internal representation for our wrapping struct around
    34  // timing histograms. It implements both kubeCollector and GaugeMetric
    35  type TimingHistogram struct {
    36  	PrometheusTimingHistogram
    37  	*TimingHistogramOpts
    38  	nowFunc func() time.Time
    39  	lazyMetric
    40  	selfCollector
    41  }
    42  
    43  var _ GaugeMetric = &TimingHistogram{}
    44  var _ Registerable = &TimingHistogram{}
    45  var _ kubeCollector = &TimingHistogram{}
    46  
    47  // NewTimingHistogram returns an object which is TimingHistogram-like. However, nothing
    48  // will be measured until the histogram is registered somewhere.
    49  func NewTimingHistogram(opts *TimingHistogramOpts) *TimingHistogram {
    50  	return NewTestableTimingHistogram(time.Now, opts)
    51  }
    52  
    53  // NewTestableTimingHistogram adds injection of the clock
    54  func NewTestableTimingHistogram(nowFunc func() time.Time, opts *TimingHistogramOpts) *TimingHistogram {
    55  	opts.StabilityLevel.setDefaults()
    56  
    57  	h := &TimingHistogram{
    58  		TimingHistogramOpts: opts,
    59  		nowFunc:             nowFunc,
    60  		lazyMetric:          lazyMetric{stabilityLevel: opts.StabilityLevel},
    61  	}
    62  	h.setPrometheusHistogram(noopMetric{})
    63  	h.lazyInit(h, BuildFQName(opts.Namespace, opts.Subsystem, opts.Name))
    64  	return h
    65  }
    66  
    67  // setPrometheusHistogram sets the underlying KubeGauge object, i.e. the thing that does the measurement.
    68  func (h *TimingHistogram) setPrometheusHistogram(histogram promext.TimingHistogram) {
    69  	h.PrometheusTimingHistogram = histogram
    70  	h.initSelfCollection(histogram)
    71  }
    72  
    73  // DeprecatedVersion returns a pointer to the Version or nil
    74  func (h *TimingHistogram) DeprecatedVersion() *semver.Version {
    75  	return parseSemver(h.TimingHistogramOpts.DeprecatedVersion)
    76  }
    77  
    78  // initializeMetric invokes the actual prometheus.Histogram object instantiation
    79  // and stores a reference to it
    80  func (h *TimingHistogram) initializeMetric() {
    81  	h.TimingHistogramOpts.annotateStabilityLevel()
    82  	// this actually creates the underlying prometheus gauge.
    83  	histogram, err := promext.NewTestableTimingHistogram(h.nowFunc, h.TimingHistogramOpts.toPromHistogramOpts())
    84  	if err != nil {
    85  		panic(err) // handle as for regular histograms
    86  	}
    87  	h.setPrometheusHistogram(histogram)
    88  }
    89  
    90  // initializeDeprecatedMetric invokes the actual prometheus.Histogram object instantiation
    91  // but modifies the Help description prior to object instantiation.
    92  func (h *TimingHistogram) initializeDeprecatedMetric() {
    93  	h.TimingHistogramOpts.markDeprecated()
    94  	h.initializeMetric()
    95  }
    96  
    97  // WithContext allows the normal TimingHistogram metric to pass in context. The context is no-op now.
    98  func (h *TimingHistogram) WithContext(ctx context.Context) GaugeMetric {
    99  	return h.PrometheusTimingHistogram
   100  }
   101  
   102  // TimingHistogramVec is the internal representation of our wrapping struct around prometheus
   103  // TimingHistogramVecs.
   104  type TimingHistogramVec struct {
   105  	*promext.TimingHistogramVec
   106  	*TimingHistogramOpts
   107  	nowFunc func() time.Time
   108  	lazyMetric
   109  	originalLabels []string
   110  }
   111  
   112  var _ GaugeVecMetric = &TimingHistogramVec{}
   113  var _ Registerable = &TimingHistogramVec{}
   114  var _ kubeCollector = &TimingHistogramVec{}
   115  
   116  // NewTimingHistogramVec returns an object which satisfies the kubeCollector, Registerable, and GaugeVecMetric interfaces
   117  // and wraps an underlying promext.TimingHistogramVec object.  Note well the way that
   118  // behavior depends on registration and whether this is hidden.
   119  func NewTimingHistogramVec(opts *TimingHistogramOpts, labels []string) *TimingHistogramVec {
   120  	return NewTestableTimingHistogramVec(time.Now, opts, labels)
   121  }
   122  
   123  // NewTestableTimingHistogramVec adds injection of the clock.
   124  func NewTestableTimingHistogramVec(nowFunc func() time.Time, opts *TimingHistogramOpts, labels []string) *TimingHistogramVec {
   125  	opts.StabilityLevel.setDefaults()
   126  
   127  	fqName := BuildFQName(opts.Namespace, opts.Subsystem, opts.Name)
   128  	allowListLock.RLock()
   129  	if allowList, ok := labelValueAllowLists[fqName]; ok {
   130  		opts.LabelValueAllowLists = allowList
   131  	}
   132  	allowListLock.RUnlock()
   133  
   134  	v := &TimingHistogramVec{
   135  		TimingHistogramVec:  noopTimingHistogramVec,
   136  		TimingHistogramOpts: opts,
   137  		nowFunc:             nowFunc,
   138  		originalLabels:      labels,
   139  		lazyMetric:          lazyMetric{stabilityLevel: opts.StabilityLevel},
   140  	}
   141  	v.lazyInit(v, fqName)
   142  	return v
   143  }
   144  
   145  // DeprecatedVersion returns a pointer to the Version or nil
   146  func (v *TimingHistogramVec) DeprecatedVersion() *semver.Version {
   147  	return parseSemver(v.TimingHistogramOpts.DeprecatedVersion)
   148  }
   149  
   150  func (v *TimingHistogramVec) initializeMetric() {
   151  	v.TimingHistogramOpts.annotateStabilityLevel()
   152  	v.TimingHistogramVec = promext.NewTestableTimingHistogramVec(v.nowFunc, v.TimingHistogramOpts.toPromHistogramOpts(), v.originalLabels...)
   153  }
   154  
   155  func (v *TimingHistogramVec) initializeDeprecatedMetric() {
   156  	v.TimingHistogramOpts.markDeprecated()
   157  	v.initializeMetric()
   158  }
   159  
   160  // WithLabelValuesChecked, if called before this vector has been registered in
   161  // at least one registry, will return a noop gauge and
   162  // an error that passes ErrIsNotRegistered.
   163  // If called on a hidden vector,
   164  // will return a noop gauge and a nil error.
   165  // If called with a syntactic problem in the labels, will
   166  // return a noop gauge and an error about the labels.
   167  // If none of the above apply, this method will return
   168  // the appropriate vector member and a nil error.
   169  func (v *TimingHistogramVec) WithLabelValuesChecked(lvs ...string) (GaugeMetric, error) {
   170  	if !v.IsCreated() {
   171  		if v.IsHidden() {
   172  			return noop, nil
   173  		}
   174  		return noop, errNotRegistered
   175  	}
   176  	if v.LabelValueAllowLists != nil {
   177  		v.LabelValueAllowLists.ConstrainToAllowedList(v.originalLabels, lvs)
   178  	}
   179  	ops, err := v.TimingHistogramVec.GetMetricWithLabelValues(lvs...)
   180  	if err != nil {
   181  		return noop, err
   182  	}
   183  	return ops.(GaugeMetric), err
   184  }
   185  
   186  // WithLabelValues calls WithLabelValuesChecked
   187  // and handles errors as follows.
   188  // An error that passes ErrIsNotRegistered is ignored
   189  // and the noop gauge is returned;
   190  // all other errors cause a panic.
   191  func (v *TimingHistogramVec) WithLabelValues(lvs ...string) GaugeMetric {
   192  	ans, err := v.WithLabelValuesChecked(lvs...)
   193  	if err == nil || ErrIsNotRegistered(err) {
   194  		return ans
   195  	}
   196  	panic(err)
   197  }
   198  
   199  // WithChecked, if called before this vector has been registered in
   200  // at least one registry, will return a noop gauge and
   201  // an error that passes ErrIsNotRegistered.
   202  // If called on a hidden vector,
   203  // will return a noop gauge and a nil error.
   204  // If called with a syntactic problem in the labels, will
   205  // return a noop gauge and an error about the labels.
   206  // If none of the above apply, this method will return
   207  // the appropriate vector member and a nil error.
   208  func (v *TimingHistogramVec) WithChecked(labels map[string]string) (GaugeMetric, error) {
   209  	if !v.IsCreated() {
   210  		if v.IsHidden() {
   211  			return noop, nil
   212  		}
   213  		return noop, errNotRegistered
   214  	}
   215  	if v.LabelValueAllowLists != nil {
   216  		v.LabelValueAllowLists.ConstrainLabelMap(labels)
   217  	}
   218  	ops, err := v.TimingHistogramVec.GetMetricWith(labels)
   219  	return ops.(GaugeMetric), err
   220  }
   221  
   222  // With calls WithChecked and handles errors as follows.
   223  // An error that passes ErrIsNotRegistered is ignored
   224  // and the noop gauge is returned;
   225  // all other errors cause a panic.
   226  func (v *TimingHistogramVec) With(labels map[string]string) GaugeMetric {
   227  	ans, err := v.WithChecked(labels)
   228  	if err == nil || ErrIsNotRegistered(err) {
   229  		return ans
   230  	}
   231  	panic(err)
   232  }
   233  
   234  // Delete deletes the metric where the variable labels are the same as those
   235  // passed in as labels. It returns true if a metric was deleted.
   236  //
   237  // It is not an error if the number and names of the Labels are inconsistent
   238  // with those of the VariableLabels in Desc. However, such inconsistent Labels
   239  // can never match an actual metric, so the method will always return false in
   240  // that case.
   241  func (v *TimingHistogramVec) Delete(labels map[string]string) bool {
   242  	if !v.IsCreated() {
   243  		return false // since we haven't created the metric, we haven't deleted a metric with the passed in values
   244  	}
   245  	return v.TimingHistogramVec.Delete(labels)
   246  }
   247  
   248  // Reset deletes all metrics in this vector.
   249  func (v *TimingHistogramVec) Reset() {
   250  	if !v.IsCreated() {
   251  		return
   252  	}
   253  
   254  	v.TimingHistogramVec.Reset()
   255  }
   256  
   257  // WithContext returns wrapped TimingHistogramVec with context
   258  func (v *TimingHistogramVec) InterfaceWithContext(ctx context.Context) GaugeVecMetric {
   259  	return &TimingHistogramVecWithContext{
   260  		ctx:                ctx,
   261  		TimingHistogramVec: v,
   262  	}
   263  }
   264  
   265  // TimingHistogramVecWithContext is the wrapper of TimingHistogramVec with context.
   266  // Currently the context is ignored.
   267  type TimingHistogramVecWithContext struct {
   268  	*TimingHistogramVec
   269  	ctx context.Context
   270  }
   271  

View as plain text