Automatic statistic registeration for metrics cache
[ric-plt/xapp-frame.git] / pkg / xapp / metrics.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package xapp
21
22 import (
23         "fmt"
24         "github.com/gorilla/mux"
25         "github.com/prometheus/client_golang/prometheus"
26         "github.com/prometheus/client_golang/prometheus/promauto"
27         "github.com/prometheus/client_golang/prometheus/promhttp"
28         "sync"
29 )
30
31 //-----------------------------------------------------------------------------
32 //
33 //-----------------------------------------------------------------------------
34 func strSliceCompare(a, b []string) bool {
35         if len(a) != len(b) {
36                 return false
37         }
38         for i, v := range a {
39                 if v != b[i] {
40                         return false
41                 }
42         }
43         return true
44 }
45
46 //-----------------------------------------------------------------------------
47 // Alias
48 //-----------------------------------------------------------------------------
49 type CounterOpts prometheus.Opts
50 type Counter prometheus.Counter
51 type Gauge prometheus.Gauge
52
53 type CounterVec struct {
54         Vec    *prometheus.CounterVec
55         Opts   CounterOpts
56         Labels []string
57 }
58
59 type GaugeVec struct {
60         Vec    *prometheus.GaugeVec
61         Opts   CounterOpts
62         Labels []string
63 }
64
65 //-----------------------------------------------------------------------------
66 //
67 //-----------------------------------------------------------------------------
68 type MetricGroupsCacheCounterRegisterer interface {
69         RegisterCounter(CounterOpts) Counter
70 }
71
72 type MetricGroupsCacheCounterRegistererFunc func(CounterOpts) Counter
73
74 func (fn MetricGroupsCacheCounterRegistererFunc) RegisterCounter(copts CounterOpts) Counter {
75         return fn(copts)
76 }
77
78 //-----------------------------------------------------------------------------
79 //
80 //-----------------------------------------------------------------------------
81 type MetricGroupsCacheGaugeRegisterer interface {
82         RegisterGauge(CounterOpts) Gauge
83 }
84
85 type MetricGroupsCacheGaugeRegistererFunc func(CounterOpts) Gauge
86
87 func (fn MetricGroupsCacheGaugeRegistererFunc) RegisterGauge(copts CounterOpts) Gauge {
88         return fn(copts)
89 }
90
91 //-----------------------------------------------------------------------------
92 //
93 //-----------------------------------------------------------------------------
94
95 type MetricGroupsCache struct {
96         sync.RWMutex //This is for map locking
97         counters     map[string]Counter
98         gauges       map[string]Gauge
99         regcnt       MetricGroupsCacheCounterRegisterer
100         reggau       MetricGroupsCacheGaugeRegisterer
101 }
102
103 func (met *MetricGroupsCache) Registerer(regcnt MetricGroupsCacheCounterRegisterer, reggau MetricGroupsCacheGaugeRegisterer) {
104         met.regcnt = regcnt
105         met.reggau = reggau
106 }
107
108 func (met *MetricGroupsCache) cReg(metric string) Counter {
109         if met.regcnt != nil {
110                 cntr := met.regcnt.RegisterCounter(CounterOpts{Name: metric, Help: "Amount of " + metric + "(auto)"})
111                 met.counters[metric] = cntr
112                 return cntr
113         }
114         return nil
115 }
116 func (met *MetricGroupsCache) gReg(metric string) Gauge {
117         if met.reggau != nil {
118                 gaug := met.reggau.RegisterGauge(CounterOpts{Name: metric, Help: "Amount of " + metric + "(auto)"})
119                 met.gauges[metric] = gaug
120                 return gaug
121         }
122         return nil
123 }
124
125 func (met *MetricGroupsCache) CIs(metric string) bool {
126         met.Lock()
127         defer met.Unlock()
128         _, ok := met.counters[metric]
129         return ok
130 }
131
132 func (met *MetricGroupsCache) CGet(metric string) Counter {
133         met.Lock()
134         defer met.Unlock()
135         cntr, ok := met.counters[metric]
136         if !ok {
137                 cntr = met.cReg(metric)
138         }
139         return cntr
140 }
141
142 func (met *MetricGroupsCache) CInc(metric string) {
143         met.Lock()
144         defer met.Unlock()
145         cntr, ok := met.counters[metric]
146         if !ok {
147                 cntr = met.cReg(metric)
148         }
149         cntr.Inc()
150 }
151
152 func (met *MetricGroupsCache) CAdd(metric string, val float64) {
153         met.Lock()
154         defer met.Unlock()
155         cntr, ok := met.counters[metric]
156         if !ok {
157                 cntr = met.cReg(metric)
158         }
159         cntr.Add(val)
160 }
161
162 func (met *MetricGroupsCache) GIs(metric string) bool {
163         met.Lock()
164         defer met.Unlock()
165         _, ok := met.gauges[metric]
166         return ok
167 }
168
169 func (met *MetricGroupsCache) GGet(metric string) Gauge {
170         met.Lock()
171         defer met.Unlock()
172         gaug, ok := met.gauges[metric]
173         if !ok {
174                 gaug = met.gReg(metric)
175         }
176         return gaug
177 }
178
179 func (met *MetricGroupsCache) GSet(metric string, val float64) {
180         met.Lock()
181         defer met.Unlock()
182         gaug, ok := met.gauges[metric]
183         if !ok {
184                 gaug = met.gReg(metric)
185         }
186         gaug.Set(val)
187 }
188
189 func (met *MetricGroupsCache) GAdd(metric string, val float64) {
190         met.Lock()
191         defer met.Unlock()
192         gaug, ok := met.gauges[metric]
193         if !ok {
194                 gaug = met.gReg(metric)
195         }
196         gaug.Add(val)
197 }
198
199 func (met *MetricGroupsCache) GInc(metric string) {
200         met.Lock()
201         defer met.Unlock()
202         gaug, ok := met.gauges[metric]
203         if !ok {
204                 gaug = met.gReg(metric)
205         }
206         gaug.Inc()
207 }
208
209 func (met *MetricGroupsCache) GDec(metric string) {
210         met.Lock()
211         defer met.Unlock()
212         gaug, ok := met.gauges[metric]
213         if !ok {
214                 gaug = met.gReg(metric)
215         }
216         gaug.Dec()
217 }
218
219 func (met *MetricGroupsCache) combineCounterGroupsWithPrefix(prefix string, srcs ...map[string]Counter) {
220         for _, src := range srcs {
221                 for k, v := range src {
222                         met.counters[prefix+k] = v
223                 }
224         }
225 }
226
227 func (met *MetricGroupsCache) CombineCounterGroupsWithPrefix(prefix string, srcs ...map[string]Counter) {
228         met.Lock()
229         defer met.Unlock()
230         met.combineCounterGroupsWithPrefix(prefix, srcs...)
231 }
232
233 func (met *MetricGroupsCache) CombineCounterGroups(srcs ...map[string]Counter) {
234         met.Lock()
235         defer met.Unlock()
236         met.combineCounterGroupsWithPrefix("", srcs...)
237 }
238
239 func (met *MetricGroupsCache) combineGaugeGroupsWithPrefix(prefix string, srcs ...map[string]Gauge) {
240         for _, src := range srcs {
241                 for k, v := range src {
242                         met.gauges[prefix+k] = v
243                 }
244         }
245 }
246
247 func (met *MetricGroupsCache) CombineGaugeGroupsWithPrefix(prefix string, srcs ...map[string]Gauge) {
248         met.Lock()
249         defer met.Unlock()
250         met.combineGaugeGroupsWithPrefix(prefix, srcs...)
251 }
252
253 func (met *MetricGroupsCache) CombineGaugeGroups(srcs ...map[string]Gauge) {
254         met.Lock()
255         defer met.Unlock()
256         met.combineGaugeGroupsWithPrefix("", srcs...)
257 }
258
259 func NewMetricGroupsCache() *MetricGroupsCache {
260         entry := &MetricGroupsCache{}
261         entry.counters = make(map[string]Counter)
262         entry.gauges = make(map[string]Gauge)
263         entry.regcnt = nil
264         entry.reggau = nil
265         return entry
266 }
267
268 func NewMetricGroupsCacheWithRegisterers(regcnt MetricGroupsCacheCounterRegisterer, reggau MetricGroupsCacheGaugeRegisterer) *MetricGroupsCache {
269         entry := NewMetricGroupsCache()
270         entry.regcnt = regcnt
271         entry.reggau = reggau
272         return entry
273 }
274
275 //-----------------------------------------------------------------------------
276 // All counters/gauges registered via Metrics instances:
277 // Counter names are build from: namespace, subsystem, metric and possible labels
278 //-----------------------------------------------------------------------------
279 var globalLock sync.Mutex
280 var cache_allcounters map[string]Counter
281 var cache_allgauges map[string]Gauge
282 var cache_allcountervects map[string]CounterVec
283 var cache_allgaugevects map[string]GaugeVec
284
285 func init() {
286         cache_allcounters = make(map[string]Counter)
287         cache_allgauges = make(map[string]Gauge)
288         cache_allcountervects = make(map[string]CounterVec)
289         cache_allgaugevects = make(map[string]GaugeVec)
290 }
291
292 //-----------------------------------------------------------------------------
293 //
294 //-----------------------------------------------------------------------------
295 type Metrics struct {
296         Namespace string
297 }
298
299 func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
300         if url == "" {
301                 url = "/ric/v1/metrics"
302         }
303         if namespace == "" {
304                 namespace = "ricxapp"
305         }
306
307         Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
308
309         // Expose 'metrics' endpoint with standard golang metrics used by prometheus
310         r.Handle(url, promhttp.Handler())
311
312         return &Metrics{Namespace: namespace}
313 }
314
315 /*
316  * Helpers
317  */
318 func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
319         labelname := ""
320         for _, lbl := range labels {
321                 if len(labelname) == 0 {
322                         labelname += lbl
323                 } else {
324                         labelname += "_" + lbl
325                 }
326         }
327         return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
328 }
329
330 //
331 //
332 //
333 func (m *Metrics) RegisterCounter(opts CounterOpts, subsytem string) Counter {
334         globalLock.Lock()
335         defer globalLock.Unlock()
336         opts.Namespace = m.Namespace
337         opts.Subsystem = subsytem
338         id := m.getFullName(prometheus.Opts(opts), []string{})
339         if _, ok := cache_allcountervects[id]; ok {
340                 Logger.Warn("Register new counter with opts: %v, name conflicts existing counter vector", opts)
341                 return nil
342         }
343         if _, ok := cache_allcounters[id]; !ok {
344                 Logger.Debug("Register new counter with opts: %v", opts)
345                 cache_allcounters[id] = promauto.NewCounter(prometheus.CounterOpts(opts))
346         }
347         return cache_allcounters[id]
348 }
349
350 //
351 //
352 //
353 func (m *Metrics) RegisterCounterGroup(optsgroup []CounterOpts, subsytem string) map[string]Counter {
354         c := make(map[string]Counter)
355         for _, opts := range optsgroup {
356                 c[opts.Name] = m.RegisterCounter(opts, subsytem)
357         }
358         return c
359 }
360
361 //
362 //
363 //
364 func (m *Metrics) RegisterLabeledCounter(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Counter {
365         globalLock.Lock()
366         defer globalLock.Unlock()
367         opts.Namespace = m.Namespace
368         opts.Subsystem = subsytem
369         vecid := m.getFullName(prometheus.Opts(opts), []string{})
370         if _, ok := cache_allcounters[vecid]; ok {
371                 Logger.Warn("Register new counter vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
372                 return nil
373         }
374         if _, ok := cache_allcountervects[vecid]; !ok {
375                 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
376                 entry := CounterVec{}
377                 entry.Opts = opts
378                 entry.Labels = labelNames
379                 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
380                 cache_allcountervects[vecid] = entry
381         }
382         entry := cache_allcountervects[vecid]
383         if strSliceCompare(entry.Labels, labelNames) == false {
384                 Logger.Warn("id:%s cached counter vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
385                 return nil
386         }
387         valid := m.getFullName(prometheus.Opts(entry.Opts), labelValues)
388         if _, ok := cache_allcounters[valid]; !ok {
389                 Logger.Debug("Register new counter from vector with opts: %v labelValues: %v", entry.Opts, labelValues)
390                 cache_allcounters[valid] = entry.Vec.WithLabelValues(labelValues...)
391         }
392         return cache_allcounters[valid]
393 }
394
395 //
396 //
397 //
398 func (m *Metrics) RegisterLabeledCounterGroup(optsgroup []CounterOpts, labelNames []string, labelValues []string, subsytem string) map[string]Counter {
399         c := make(map[string]Counter)
400         for _, opts := range optsgroup {
401                 c[opts.Name] = m.RegisterLabeledCounter(opts, labelNames, labelValues, subsytem)
402         }
403         return c
404 }
405
406 //
407 //
408 //
409 func (m *Metrics) RegisterGauge(opts CounterOpts, subsytem string) Gauge {
410         globalLock.Lock()
411         defer globalLock.Unlock()
412         opts.Namespace = m.Namespace
413         opts.Subsystem = subsytem
414         id := m.getFullName(prometheus.Opts(opts), []string{})
415         if _, ok := cache_allgaugevects[id]; ok {
416                 Logger.Warn("Register new gauge with opts: %v, name conflicts existing gauge vector", opts)
417                 return nil
418         }
419         if _, ok := cache_allgauges[id]; !ok {
420                 Logger.Debug("Register new gauge with opts: %v", opts)
421                 cache_allgauges[id] = promauto.NewGauge(prometheus.GaugeOpts(opts))
422         }
423         return cache_allgauges[id]
424 }
425
426 //
427 //
428 //
429 func (m *Metrics) RegisterGaugeGroup(optsgroup []CounterOpts, subsytem string) map[string]Gauge {
430         c := make(map[string]Gauge)
431         for _, opts := range optsgroup {
432                 c[opts.Name] = m.RegisterGauge(opts, subsytem)
433         }
434         return c
435 }
436
437 //
438 //
439 //
440 func (m *Metrics) RegisterLabeledGauge(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Gauge {
441         globalLock.Lock()
442         defer globalLock.Unlock()
443         opts.Namespace = m.Namespace
444         opts.Subsystem = subsytem
445         vecid := m.getFullName(prometheus.Opts(opts), []string{})
446         if _, ok := cache_allgauges[vecid]; ok {
447                 Logger.Warn("Register new gauge vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
448                 return nil
449         }
450         if _, ok := cache_allgaugevects[vecid]; !ok {
451                 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
452                 entry := GaugeVec{}
453                 entry.Opts = opts
454                 entry.Labels = labelNames
455                 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
456                 cache_allgaugevects[vecid] = entry
457         }
458         entry := cache_allgaugevects[vecid]
459         if strSliceCompare(entry.Labels, labelNames) == false {
460                 Logger.Warn("id:%s cached gauge vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
461                 return nil
462         }
463         valid := m.getFullName(prometheus.Opts(entry.Opts), labelValues)
464         if _, ok := cache_allgauges[valid]; !ok {
465                 Logger.Debug("Register new gauge from vector with opts: %v labelValues: %v", entry.Opts, labelValues)
466                 cache_allgauges[valid] = entry.Vec.WithLabelValues(labelValues...)
467         }
468         return cache_allgauges[valid]
469 }
470
471 //
472 //
473 //
474 func (m *Metrics) RegisterLabeledGaugeGroup(optsgroup []CounterOpts, labelNames []string, labelValues []string, subsytem string) map[string]Gauge {
475         c := make(map[string]Gauge)
476         for _, opts := range optsgroup {
477                 c[opts.Name] = m.RegisterLabeledGauge(opts, labelNames, labelValues, subsytem)
478         }
479         return c
480 }
481
482 /*
483  * Handling counter vectors
484  *
485  * Examples:
486
487   //---------
488         vec := Metric.RegisterCounterVec(
489                 CounterOpts{Name: "counter0", Help: "counter0"},
490                 []string{"host"},
491                 "SUBSYSTEM")
492
493         stat:=Metric.GetCounterFromVect([]string{"localhost:8888"},vec)
494         stat.Inc()
495
496   //---------
497         vec := Metric.RegisterCounterVecGroup(
498                 []CounterOpts{
499                         {Name: "counter1", Help: "counter1"},
500                         {Name: "counter2", Help: "counter2"},
501                 },
502                 []string{"host"},
503                 "SUBSYSTEM")
504
505         stats:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
506         stats["counter1"].Inc()
507 */
508
509 // Deprecated: Use RegisterLabeledCounter
510 func (m *Metrics) RegisterCounterVec(opts CounterOpts, labelNames []string, subsytem string) CounterVec {
511         globalLock.Lock()
512         defer globalLock.Unlock()
513         opts.Namespace = m.Namespace
514         opts.Subsystem = subsytem
515         vecid := m.getFullName(prometheus.Opts(opts), []string{})
516         if _, ok := cache_allcounters[vecid]; ok {
517                 Logger.Warn("Register new counter vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
518                 return CounterVec{}
519         }
520         if _, ok := cache_allcountervects[vecid]; !ok {
521                 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
522                 entry := CounterVec{}
523                 entry.Opts = opts
524                 entry.Labels = labelNames
525                 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
526                 cache_allcountervects[vecid] = entry
527         }
528         entry := cache_allcountervects[vecid]
529         if strSliceCompare(entry.Labels, labelNames) == false {
530                 Logger.Warn("id:%s cached counter vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
531                 return CounterVec{}
532         }
533         return entry
534 }
535
536 // Deprecated: Use RegisterLabeledCounterGroup
537 func (m *Metrics) RegisterCounterVecGroup(optsgroup []CounterOpts, labelNames []string, subsytem string) map[string]CounterVec {
538         c := make(map[string]CounterVec)
539         for _, opts := range optsgroup {
540                 ret := m.RegisterCounterVec(opts, labelNames, subsytem)
541                 if ret.Vec != nil {
542                         c[opts.Name] = ret
543                 }
544         }
545         return c
546 }
547
548 // Deprecated: Use RegisterLabeledCounter
549 func (m *Metrics) GetCounterFromVect(labelValues []string, vec CounterVec) (c Counter) {
550         globalLock.Lock()
551         defer globalLock.Unlock()
552         valid := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
553         if _, ok := cache_allcounters[valid]; !ok {
554                 Logger.Debug("Register new counter from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
555                 cache_allcounters[valid] = vec.Vec.WithLabelValues(labelValues...)
556         }
557         return cache_allcounters[valid]
558 }
559
560 // Deprecated: Use RegisterLabeledCounterGroup
561 func (m *Metrics) GetCounterGroupFromVects(labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
562         c := make(map[string]Counter)
563         for _, vect := range vects {
564                 for name, vec := range vect {
565                         c[name] = m.GetCounterFromVect(labelValues, vec)
566                 }
567         }
568         return c
569 }
570
571 // Deprecated: Use RegisterLabeledCounterGroup
572 func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
573         c := make(map[string]Counter)
574         for _, vect := range vects {
575                 for name, vec := range vect {
576                         c[prefix+name] = m.GetCounterFromVect(labelValues, vec)
577                 }
578         }
579         return c
580 }
581
582 /*
583  * Handling gauge vectors
584  *
585  * Examples:
586
587   //---------
588         vec := Metric.RegisterGaugeVec(
589                 CounterOpts{Name: "gauge0", Help: "gauge0"},
590                 []string{"host"},
591                 "SUBSYSTEM")
592
593         stat:=Metric.GetGaugeFromVect([]string{"localhost:8888"},vec)
594         stat.Inc()
595
596   //---------
597         vecgrp := Metric.RegisterGaugeVecGroup(
598                 []CounterOpts{
599                         {Name: "gauge1", Help: "gauge1"},
600                         {Name: "gauge2", Help: "gauge2"},
601                 },
602                 []string{"host"},
603                 "SUBSYSTEM")
604
605         stats:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vecgrp)
606         stats["gauge1"].Inc()
607 */
608
609 // Deprecated: Use RegisterLabeledGauge
610 func (m *Metrics) RegisterGaugeVec(opts CounterOpts, labelNames []string, subsytem string) GaugeVec {
611         globalLock.Lock()
612         defer globalLock.Unlock()
613         opts.Namespace = m.Namespace
614         opts.Subsystem = subsytem
615         vecid := m.getFullName(prometheus.Opts(opts), []string{})
616         if _, ok := cache_allgauges[vecid]; ok {
617                 Logger.Warn("Register new gauge vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
618                 return GaugeVec{}
619         }
620         if _, ok := cache_allgaugevects[vecid]; !ok {
621                 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
622                 entry := GaugeVec{}
623                 entry.Opts = opts
624                 entry.Labels = labelNames
625                 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
626                 cache_allgaugevects[vecid] = entry
627         }
628         entry := cache_allgaugevects[vecid]
629         if strSliceCompare(entry.Labels, labelNames) == false {
630                 Logger.Warn("id:%s cached gauge vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
631                 return GaugeVec{}
632         }
633         return entry
634 }
635
636 // Deprecated: Use RegisterLabeledGaugeGroup
637 func (m *Metrics) RegisterGaugeVecGroup(optsgroup []CounterOpts, labelNames []string, subsytem string) map[string]GaugeVec {
638         c := make(map[string]GaugeVec)
639         for _, opts := range optsgroup {
640                 ret := m.RegisterGaugeVec(opts, labelNames, subsytem)
641                 if ret.Vec != nil {
642                         c[opts.Name] = ret
643                 }
644
645         }
646         return c
647 }
648
649 // Deprecated: Use RegisterLabeledGauge
650 func (m *Metrics) GetGaugeFromVect(labelValues []string, vec GaugeVec) Gauge {
651         globalLock.Lock()
652         defer globalLock.Unlock()
653         valid := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
654         if _, ok := cache_allgauges[valid]; !ok {
655                 Logger.Debug("Register new gauge from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
656                 cache_allgauges[valid] = vec.Vec.WithLabelValues(labelValues...)
657         }
658         return cache_allgauges[valid]
659 }
660
661 // Deprecated: Use RegisterLabeledGaugeGroup
662 func (m *Metrics) GetGaugeGroupFromVects(labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
663         c := make(map[string]Gauge)
664         for _, vect := range vects {
665                 for name, vec := range vect {
666                         c[name] = m.GetGaugeFromVect(labelValues, vec)
667                 }
668         }
669         return c
670 }
671
672 // Deprecated: Use RegisterLabeledGaugeGroup
673 func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
674         c := make(map[string]Gauge)
675         for _, vect := range vects {
676                 for name, vec := range vect {
677                         c[prefix+name] = m.GetGaugeFromVect(labelValues, vec)
678                 }
679         }
680         return c
681 }