|
| 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 | + "github.com/blang/semver" |
| 21 | + "github.com/prometheus/client_golang/prometheus" |
| 22 | +) |
| 23 | + |
| 24 | +// Counter is our internal representation for our wrapping struct around prometheus |
| 25 | +// counters. Counter implements both KubeCollector and CounterMetric. |
| 26 | +type Counter struct { |
| 27 | + CounterMetric |
| 28 | + *CounterOpts |
| 29 | + lazyMetric |
| 30 | + selfCollector |
| 31 | +} |
| 32 | + |
| 33 | +// NewCounter returns an object which satisfies the KubeCollector and CounterMetric interfaces. |
| 34 | +// However, the object returned will not measure anything unless the collector is first |
| 35 | +// registered, since the metric is lazily instantiated. |
| 36 | +func NewCounter(opts *CounterOpts) *Counter { |
| 37 | + // todo: handle defaulting better |
| 38 | + if opts.StabilityLevel == "" { |
| 39 | + opts.StabilityLevel = ALPHA |
| 40 | + } |
| 41 | + kc := &Counter{ |
| 42 | + CounterOpts: opts, |
| 43 | + lazyMetric: lazyMetric{}, |
| 44 | + } |
| 45 | + kc.setPrometheusCounter(noop) |
| 46 | + kc.lazyInit(kc) |
| 47 | + return kc |
| 48 | +} |
| 49 | + |
| 50 | +// setPrometheusCounter sets the underlying CounterMetric object, i.e. the thing that does the measurement. |
| 51 | +func (c *Counter) setPrometheusCounter(counter prometheus.Counter) { |
| 52 | + c.CounterMetric = counter |
| 53 | + c.initSelfCollection(counter) |
| 54 | +} |
| 55 | + |
| 56 | +// DeprecatedVersion returns a pointer to the Version or nil |
| 57 | +func (c *Counter) DeprecatedVersion() *semver.Version { |
| 58 | + return c.CounterOpts.DeprecatedVersion |
| 59 | +} |
| 60 | + |
| 61 | +// initializeMetric invocation creates the actual underlying Counter. Until this method is called |
| 62 | +// the underlying counter is a no-op. |
| 63 | +func (c *Counter) initializeMetric() { |
| 64 | + c.CounterOpts.annotateStabilityLevel() |
| 65 | + // this actually creates the underlying prometheus counter. |
| 66 | + c.setPrometheusCounter(prometheus.NewCounter(c.CounterOpts.toPromCounterOpts())) |
| 67 | +} |
| 68 | + |
| 69 | +// initializeDeprecatedMetric invocation creates the actual (but deprecated) Counter. Until this method |
| 70 | +// is called the underlying counter is a no-op. |
| 71 | +func (c *Counter) initializeDeprecatedMetric() { |
| 72 | + c.CounterOpts.markDeprecated() |
| 73 | + c.initializeMetric() |
| 74 | +} |
| 75 | + |
| 76 | +// CounterVec is the internal representation of our wrapping struct around prometheus |
| 77 | +// counterVecs. CounterVec implements both KubeCollector and CounterVecMetric. |
| 78 | +type CounterVec struct { |
| 79 | + *prometheus.CounterVec |
| 80 | + *CounterOpts |
| 81 | + lazyMetric |
| 82 | + originalLabels []string |
| 83 | +} |
| 84 | + |
| 85 | +// NewCounterVec returns an object which satisfies the KubeCollector and CounterVecMetric interfaces. |
| 86 | +// However, the object returned will not measure anything unless the collector is first |
| 87 | +// registered, since the metric is lazily instantiated. |
| 88 | +func NewCounterVec(opts *CounterOpts, labels []string) *CounterVec { |
| 89 | + cv := &CounterVec{ |
| 90 | + CounterVec: noopCounterVec, |
| 91 | + CounterOpts: opts, |
| 92 | + originalLabels: labels, |
| 93 | + lazyMetric: lazyMetric{}, |
| 94 | + } |
| 95 | + cv.lazyInit(cv) |
| 96 | + return cv |
| 97 | +} |
| 98 | + |
| 99 | +// DeprecatedVersion returns a pointer to the Version or nil |
| 100 | +func (v *CounterVec) DeprecatedVersion() *semver.Version { |
| 101 | + return v.CounterOpts.DeprecatedVersion |
| 102 | +} |
| 103 | + |
| 104 | +// initializeMetric invocation creates the actual underlying CounterVec. Until this method is called |
| 105 | +// the underlying counterVec is a no-op. |
| 106 | +func (v *CounterVec) initializeMetric() { |
| 107 | + v.CounterVec = prometheus.NewCounterVec(v.CounterOpts.toPromCounterOpts(), v.originalLabels) |
| 108 | +} |
| 109 | + |
| 110 | +// initializeDeprecatedMetric invocation creates the actual (but deprecated) CounterVec. Until this method is called |
| 111 | +// the underlying counterVec is a no-op. |
| 112 | +func (v *CounterVec) initializeDeprecatedMetric() { |
| 113 | + v.CounterOpts.markDeprecated() |
| 114 | + v.initializeMetric() |
| 115 | +} |
| 116 | + |
| 117 | +// Default Prometheus behavior actually results in the creation of a new metric |
| 118 | +// if a metric with the unique label values is not found in the underlying stored metricMap. |
| 119 | +// This means that if this function is called but the underlying metric is not registered |
| 120 | +// (which means it will never be exposed externally nor consumed), the metric will exist in memory |
| 121 | +// for perpetuity (i.e. throughout application lifecycle). |
| 122 | +// |
| 123 | +// For reference: https://github.com/prometheus/client_golang/blob/v0.9.2/prometheus/counter.go#L179-L197 |
| 124 | + |
| 125 | +// WithLabelValues returns the Counter for the given slice of label |
| 126 | +// values (same order as the VariableLabels in Desc). If that combination of |
| 127 | +// label values is accessed for the first time, a new Counter is created IFF the counterVec |
| 128 | +// has been registered to a metrics registry. |
| 129 | +func (v *CounterVec) WithLabelValues(lvs ...string) CounterMetric { |
| 130 | + if !v.IsCreated() { |
| 131 | + return noop // return no-op counter |
| 132 | + } |
| 133 | + return v.CounterVec.WithLabelValues(lvs...) |
| 134 | +} |
| 135 | + |
| 136 | +// With returns the Counter for the given Labels map (the label names |
| 137 | +// must match those of the VariableLabels in Desc). If that label map is |
| 138 | +// accessed for the first time, a new Counter is created IFF the counterVec has |
| 139 | +// been registered to a metrics registry. |
| 140 | +func (v *CounterVec) With(labels prometheus.Labels) CounterMetric { |
| 141 | + if !v.IsCreated() { |
| 142 | + return noop // return no-op counter |
| 143 | + } |
| 144 | + return v.CounterVec.With(labels) |
| 145 | +} |
0 commit comments