1
16
17 package metrics
18
19 import (
20 "fmt"
21 "sync"
22 "sync/atomic"
23
24 "github.com/blang/semver/v4"
25 "github.com/prometheus/client_golang/prometheus"
26 dto "github.com/prometheus/client_model/go"
27
28 apimachineryversion "k8s.io/apimachinery/pkg/version"
29 "k8s.io/component-base/version"
30 )
31
32 var (
33 showHiddenOnce sync.Once
34 disabledMetricsLock sync.RWMutex
35 showHidden atomic.Bool
36 registries []*kubeRegistry
37 registriesLock sync.RWMutex
38 disabledMetrics = map[string]struct{}{}
39
40 registeredMetricsTotal = NewCounterVec(
41 &CounterOpts{
42 Name: "registered_metrics_total",
43 Help: "The count of registered metrics broken by stability level and deprecation version.",
44 StabilityLevel: BETA,
45 },
46 []string{"stability_level", "deprecated_version"},
47 )
48
49 disabledMetricsTotal = NewCounter(
50 &CounterOpts{
51 Name: "disabled_metrics_total",
52 Help: "The count of disabled metrics.",
53 StabilityLevel: BETA,
54 },
55 )
56
57 hiddenMetricsTotal = NewCounter(
58 &CounterOpts{
59 Name: "hidden_metrics_total",
60 Help: "The count of hidden metrics.",
61 StabilityLevel: BETA,
62 },
63 )
64
65 cardinalityEnforcementUnexpectedCategorizationsTotal = NewCounter(
66 &CounterOpts{
67 Name: "cardinality_enforcement_unexpected_categorizations_total",
68 Help: "The count of unexpected categorizations during cardinality enforcement.",
69 StabilityLevel: ALPHA,
70 },
71 )
72 )
73
74
75
76 func shouldHide(currentVersion *semver.Version, deprecatedVersion *semver.Version) bool {
77 guardVersion, err := semver.Make(fmt.Sprintf("%d.%d.0", currentVersion.Major, currentVersion.Minor))
78 if err != nil {
79 panic("failed to make version from current version")
80 }
81
82 if deprecatedVersion.LT(guardVersion) {
83 return true
84 }
85
86 return false
87 }
88
89
90 func ValidateShowHiddenMetricsVersion(v string) []error {
91 err := validateShowHiddenMetricsVersion(parseVersion(version.Get()), v)
92 if err != nil {
93 return []error{err}
94 }
95
96 return nil
97 }
98
99 func SetDisabledMetric(name string) {
100 disabledMetricsLock.Lock()
101 defer disabledMetricsLock.Unlock()
102 disabledMetrics[name] = struct{}{}
103 disabledMetricsTotal.Inc()
104 }
105
106
107
108 func SetShowHidden() {
109 showHiddenOnce.Do(func() {
110 showHidden.Store(true)
111
112
113 for _, r := range registries {
114 r.enableHiddenCollectors()
115 r.enableHiddenStableCollectors()
116 }
117 })
118 }
119
120
121
122
123 func ShouldShowHidden() bool {
124 return showHidden.Load()
125 }
126
127
128
129 type Registerable interface {
130 prometheus.Collector
131
132
133 Create(version *semver.Version) bool
134
135
136 ClearState()
137
138
139 FQName() string
140 }
141
142 type resettable interface {
143 Reset()
144 }
145
146
147
148 type KubeRegistry interface {
149
150 RawMustRegister(...prometheus.Collector)
151
152 CustomRegister(c StableCollector) error
153
154 CustomMustRegister(cs ...StableCollector)
155
156 Register(Registerable) error
157
158 MustRegister(...Registerable)
159
160 Unregister(collector Collector) bool
161
162 Gather() ([]*dto.MetricFamily, error)
163
164
165 Reset()
166
167 RegisterMetaMetrics()
168
169 Registerer() prometheus.Registerer
170
171 Gatherer() prometheus.Gatherer
172 }
173
174
175
176
177 type kubeRegistry struct {
178 PromRegistry
179 version semver.Version
180 hiddenCollectors map[string]Registerable
181 stableCollectors []StableCollector
182 hiddenCollectorsLock sync.RWMutex
183 stableCollectorsLock sync.RWMutex
184 resetLock sync.RWMutex
185 resettables []resettable
186 }
187
188
189
190
191
192
193 func (kr *kubeRegistry) Register(c Registerable) error {
194 if c.Create(&kr.version) {
195 defer kr.addResettable(c)
196 return kr.PromRegistry.Register(c)
197 }
198
199 kr.trackHiddenCollector(c)
200 return nil
201 }
202
203
204 func (kr *kubeRegistry) Registerer() prometheus.Registerer {
205 return kr.PromRegistry
206 }
207
208
209 func (kr *kubeRegistry) Gatherer() prometheus.Gatherer {
210 return kr.PromRegistry
211 }
212
213
214
215
216 func (kr *kubeRegistry) MustRegister(cs ...Registerable) {
217 metrics := make([]prometheus.Collector, 0, len(cs))
218 for _, c := range cs {
219 if c.Create(&kr.version) {
220 metrics = append(metrics, c)
221 kr.addResettable(c)
222 } else {
223 kr.trackHiddenCollector(c)
224 }
225 }
226 kr.PromRegistry.MustRegister(metrics...)
227 }
228
229
230 func (kr *kubeRegistry) CustomRegister(c StableCollector) error {
231 kr.trackStableCollectors(c)
232 defer kr.addResettable(c)
233 if c.Create(&kr.version, c) {
234 return kr.PromRegistry.Register(c)
235 }
236 return nil
237 }
238
239
240
241
242 func (kr *kubeRegistry) CustomMustRegister(cs ...StableCollector) {
243 kr.trackStableCollectors(cs...)
244 collectors := make([]prometheus.Collector, 0, len(cs))
245 for _, c := range cs {
246 if c.Create(&kr.version, c) {
247 kr.addResettable(c)
248 collectors = append(collectors, c)
249 }
250 }
251 kr.PromRegistry.MustRegister(collectors...)
252 }
253
254
255
256
257
258
259 func (kr *kubeRegistry) RawMustRegister(cs ...prometheus.Collector) {
260 kr.PromRegistry.MustRegister(cs...)
261 for _, c := range cs {
262 kr.addResettable(c)
263 }
264 }
265
266
267
268 func (kr *kubeRegistry) addResettable(i interface{}) {
269 kr.resetLock.Lock()
270 defer kr.resetLock.Unlock()
271 if resettable, ok := i.(resettable); ok {
272 kr.resettables = append(kr.resettables, resettable)
273 }
274 }
275
276
277
278
279
280
281
282 func (kr *kubeRegistry) Unregister(collector Collector) bool {
283 return kr.PromRegistry.Unregister(collector)
284 }
285
286
287
288
289
290
291
292
293 func (kr *kubeRegistry) Gather() ([]*dto.MetricFamily, error) {
294 return kr.PromRegistry.Gather()
295 }
296
297
298 func (kr *kubeRegistry) trackHiddenCollector(c Registerable) {
299 kr.hiddenCollectorsLock.Lock()
300 defer kr.hiddenCollectorsLock.Unlock()
301
302 kr.hiddenCollectors[c.FQName()] = c
303 hiddenMetricsTotal.Inc()
304 }
305
306
307 func (kr *kubeRegistry) trackStableCollectors(cs ...StableCollector) {
308 kr.stableCollectorsLock.Lock()
309 defer kr.stableCollectorsLock.Unlock()
310
311 kr.stableCollectors = append(kr.stableCollectors, cs...)
312 }
313
314
315 func (kr *kubeRegistry) enableHiddenCollectors() {
316 if len(kr.hiddenCollectors) == 0 {
317 return
318 }
319
320 kr.hiddenCollectorsLock.Lock()
321 cs := make([]Registerable, 0, len(kr.hiddenCollectors))
322
323 for _, c := range kr.hiddenCollectors {
324 c.ClearState()
325 cs = append(cs, c)
326 }
327
328 kr.hiddenCollectors = make(map[string]Registerable)
329 kr.hiddenCollectorsLock.Unlock()
330 kr.MustRegister(cs...)
331 }
332
333
334
335 func (kr *kubeRegistry) enableHiddenStableCollectors() {
336 if len(kr.stableCollectors) == 0 {
337 return
338 }
339
340 kr.stableCollectorsLock.Lock()
341
342 cs := make([]StableCollector, 0, len(kr.stableCollectors))
343 for _, c := range kr.stableCollectors {
344 if len(c.HiddenMetrics()) > 0 {
345 kr.Unregister(c)
346 c.ClearState()
347 cs = append(cs, c)
348 }
349 }
350
351 kr.stableCollectors = nil
352 kr.stableCollectorsLock.Unlock()
353 kr.CustomMustRegister(cs...)
354 }
355
356
357 func (kr *kubeRegistry) Reset() {
358 kr.resetLock.RLock()
359 defer kr.resetLock.RUnlock()
360 for _, r := range kr.resettables {
361 r.Reset()
362 }
363 }
364
365
366 var BuildVersion = version.Get
367
368 func newKubeRegistry(v apimachineryversion.Info) *kubeRegistry {
369 r := &kubeRegistry{
370 PromRegistry: prometheus.NewRegistry(),
371 version: parseVersion(v),
372 hiddenCollectors: make(map[string]Registerable),
373 resettables: make([]resettable, 0),
374 }
375
376 registriesLock.Lock()
377 defer registriesLock.Unlock()
378 registries = append(registries, r)
379
380 return r
381 }
382
383
384 func NewKubeRegistry() KubeRegistry {
385 r := newKubeRegistry(BuildVersion())
386 return r
387 }
388
389 func (r *kubeRegistry) RegisterMetaMetrics() {
390 r.MustRegister(registeredMetricsTotal)
391 r.MustRegister(disabledMetricsTotal)
392 r.MustRegister(hiddenMetricsTotal)
393 r.MustRegister(cardinalityEnforcementUnexpectedCategorizationsTotal)
394 }
395
View as plain text