ef5ba305e91e2e9e7beb36f64140aef425e28368
[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         Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
304
305         // Expose 'metrics' endpoint with standard golang metrics used by prometheus
306         r.Handle(url, promhttp.Handler())
307
308         return &Metrics{Namespace: namespace}
309 }
310
311 /*
312  * Helpers
313  */
314 func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
315         labelname := ""
316         for _, lbl := range labels {
317                 if len(labelname) == 0 {
318                         labelname += lbl
319                 } else {
320                         labelname += "_" + lbl
321                 }
322         }
323         return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
324 }
325
326 //
327 //
328 //
329 func (m *Metrics) RegisterCounter(opts CounterOpts, subsytem string) Counter {
330         globalLock.Lock()
331         defer globalLock.Unlock()
332         opts.Namespace = m.Namespace
333         opts.Subsystem = subsytem
334         id := m.getFullName(prometheus.Opts(opts), []string{})
335         if _, ok := cache_allcountervects[id]; ok {
336                 Logger.Warn("Register new counter with opts: %v, name conflicts existing counter vector", opts)
337                 return nil
338         }
339         if _, ok := cache_allcounters[id]; !ok {
340                 Logger.Debug("Register new counter with opts: %v", opts)
341                 cache_allcounters[id] = promauto.NewCounter(prometheus.CounterOpts(opts))
342         }
343         return cache_allcounters[id]
344 }
345
346 //
347 //
348 //
349 func (m *Metrics) RegisterCounterGroup(optsgroup []CounterOpts, subsytem string) map[string]Counter {
350         c := make(map[string]Counter)
351         for _, opts := range optsgroup {
352                 c[opts.Name] = m.RegisterCounter(opts, subsytem)
353         }
354         return c
355 }
356
357 //
358 //
359 //
360 func (m *Metrics) RegisterLabeledCounter(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Counter {
361         globalLock.Lock()
362         defer globalLock.Unlock()
363         opts.Namespace = m.Namespace
364         opts.Subsystem = subsytem
365         vecid := m.getFullName(prometheus.Opts(opts), []string{})
366         if _, ok := cache_allcounters[vecid]; ok {
367                 Logger.Warn("Register new counter vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
368                 return nil
369         }
370         if _, ok := cache_allcountervects[vecid]; !ok {
371                 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
372                 entry := CounterVec{}
373                 entry.Opts = opts
374                 entry.Labels = labelNames
375                 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
376                 cache_allcountervects[vecid] = entry
377         }
378         entry := cache_allcountervects[vecid]
379         if strSliceCompare(entry.Labels, labelNames) == false {
380                 Logger.Warn("id:%s cached counter vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
381                 return nil
382         }
383         valid := m.getFullName(prometheus.Opts(entry.Opts), labelValues)
384         if _, ok := cache_allcounters[valid]; !ok {
385                 Logger.Debug("Register new counter from vector with opts: %v labelValues: %v", entry.Opts, labelValues)
386                 cache_allcounters[valid] = entry.Vec.WithLabelValues(labelValues...)
387         }
388         return cache_allcounters[valid]
389 }
390
391 //
392 //
393 //
394 func (m *Metrics) RegisterLabeledCounterGroup(optsgroup []CounterOpts, labelNames []string, labelValues []string, subsytem string) map[string]Counter {
395         c := make(map[string]Counter)
396         for _, opts := range optsgroup {
397                 c[opts.Name] = m.RegisterLabeledCounter(opts, labelNames, labelValues, subsytem)
398         }
399         return c
400 }
401
402 //
403 //
404 //
405 func (m *Metrics) RegisterGauge(opts CounterOpts, subsytem string) Gauge {
406         globalLock.Lock()
407         defer globalLock.Unlock()
408         opts.Namespace = m.Namespace
409         opts.Subsystem = subsytem
410         id := m.getFullName(prometheus.Opts(opts), []string{})
411         if _, ok := cache_allgaugevects[id]; ok {
412                 Logger.Warn("Register new gauge with opts: %v, name conflicts existing gauge vector", opts)
413                 return nil
414         }
415         if _, ok := cache_allgauges[id]; !ok {
416                 Logger.Debug("Register new gauge with opts: %v", opts)
417                 cache_allgauges[id] = promauto.NewGauge(prometheus.GaugeOpts(opts))
418         }
419         return cache_allgauges[id]
420 }
421
422 //
423 //
424 //
425 func (m *Metrics) RegisterGaugeGroup(optsgroup []CounterOpts, subsytem string) map[string]Gauge {
426         c := make(map[string]Gauge)
427         for _, opts := range optsgroup {
428                 c[opts.Name] = m.RegisterGauge(opts, subsytem)
429         }
430         return c
431 }
432
433 //
434 //
435 //
436 func (m *Metrics) RegisterLabeledGauge(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Gauge {
437         globalLock.Lock()
438         defer globalLock.Unlock()
439         opts.Namespace = m.Namespace
440         opts.Subsystem = subsytem
441         vecid := m.getFullName(prometheus.Opts(opts), []string{})
442         if _, ok := cache_allgauges[vecid]; ok {
443                 Logger.Warn("Register new gauge vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
444                 return nil
445         }
446         if _, ok := cache_allgaugevects[vecid]; !ok {
447                 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
448                 entry := GaugeVec{}
449                 entry.Opts = opts
450                 entry.Labels = labelNames
451                 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
452                 cache_allgaugevects[vecid] = entry
453         }
454         entry := cache_allgaugevects[vecid]
455         if strSliceCompare(entry.Labels, labelNames) == false {
456                 Logger.Warn("id:%s cached gauge vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
457                 return nil
458         }
459         valid := m.getFullName(prometheus.Opts(entry.Opts), labelValues)
460         if _, ok := cache_allgauges[valid]; !ok {
461                 Logger.Debug("Register new gauge from vector with opts: %v labelValues: %v", entry.Opts, labelValues)
462                 cache_allgauges[valid] = entry.Vec.WithLabelValues(labelValues...)
463         }
464         return cache_allgauges[valid]
465 }
466
467 //
468 //
469 //
470 func (m *Metrics) RegisterLabeledGaugeGroup(optsgroup []CounterOpts, labelNames []string, labelValues []string, subsytem string) map[string]Gauge {
471         c := make(map[string]Gauge)
472         for _, opts := range optsgroup {
473                 c[opts.Name] = m.RegisterLabeledGauge(opts, labelNames, labelValues, subsytem)
474         }
475         return c
476 }
477
478 /*
479  * Handling counter vectors
480  *
481  * Examples:
482
483   //---------
484         vec := Metric.RegisterCounterVec(
485                 CounterOpts{Name: "counter0", Help: "counter0"},
486                 []string{"host"},
487                 "SUBSYSTEM")
488
489         stat:=Metric.GetCounterFromVect([]string{"localhost:8888"},vec)
490         stat.Inc()
491
492   //---------
493         vec := Metric.RegisterCounterVecGroup(
494                 []CounterOpts{
495                         {Name: "counter1", Help: "counter1"},
496                         {Name: "counter2", Help: "counter2"},
497                 },
498                 []string{"host"},
499                 "SUBSYSTEM")
500
501         stats:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
502         stats["counter1"].Inc()
503 */
504
505 // Deprecated: Use RegisterLabeledCounter
506 func (m *Metrics) RegisterCounterVec(opts CounterOpts, labelNames []string, subsytem string) CounterVec {
507         globalLock.Lock()
508         defer globalLock.Unlock()
509         opts.Namespace = m.Namespace
510         opts.Subsystem = subsytem
511         vecid := m.getFullName(prometheus.Opts(opts), []string{})
512         if _, ok := cache_allcounters[vecid]; ok {
513                 Logger.Warn("Register new counter vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
514                 return CounterVec{}
515         }
516         if _, ok := cache_allcountervects[vecid]; !ok {
517                 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
518                 entry := CounterVec{}
519                 entry.Opts = opts
520                 entry.Labels = labelNames
521                 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
522                 cache_allcountervects[vecid] = entry
523         }
524         entry := cache_allcountervects[vecid]
525         if strSliceCompare(entry.Labels, labelNames) == false {
526                 Logger.Warn("id:%s cached counter vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
527                 return CounterVec{}
528         }
529         return entry
530 }
531
532 // Deprecated: Use RegisterLabeledCounterGroup
533 func (m *Metrics) RegisterCounterVecGroup(optsgroup []CounterOpts, labelNames []string, subsytem string) map[string]CounterVec {
534         c := make(map[string]CounterVec)
535         for _, opts := range optsgroup {
536                 ret := m.RegisterCounterVec(opts, labelNames, subsytem)
537                 if ret.Vec != nil {
538                         c[opts.Name] = ret
539                 }
540         }
541         return c
542 }
543
544 // Deprecated: Use RegisterLabeledCounter
545 func (m *Metrics) GetCounterFromVect(labelValues []string, vec CounterVec) (c Counter) {
546         globalLock.Lock()
547         defer globalLock.Unlock()
548         valid := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
549         if _, ok := cache_allcounters[valid]; !ok {
550                 Logger.Debug("Register new counter from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
551                 cache_allcounters[valid] = vec.Vec.WithLabelValues(labelValues...)
552         }
553         return cache_allcounters[valid]
554 }
555
556 // Deprecated: Use RegisterLabeledCounterGroup
557 func (m *Metrics) GetCounterGroupFromVects(labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
558         c := make(map[string]Counter)
559         for _, vect := range vects {
560                 for name, vec := range vect {
561                         c[name] = m.GetCounterFromVect(labelValues, vec)
562                 }
563         }
564         return c
565 }
566
567 // Deprecated: Use RegisterLabeledCounterGroup
568 func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
569         c := make(map[string]Counter)
570         for _, vect := range vects {
571                 for name, vec := range vect {
572                         c[prefix+name] = m.GetCounterFromVect(labelValues, vec)
573                 }
574         }
575         return c
576 }
577
578 /*
579  * Handling gauge vectors
580  *
581  * Examples:
582
583   //---------
584         vec := Metric.RegisterGaugeVec(
585                 CounterOpts{Name: "gauge0", Help: "gauge0"},
586                 []string{"host"},
587                 "SUBSYSTEM")
588
589         stat:=Metric.GetGaugeFromVect([]string{"localhost:8888"},vec)
590         stat.Inc()
591
592   //---------
593         vecgrp := Metric.RegisterGaugeVecGroup(
594                 []CounterOpts{
595                         {Name: "gauge1", Help: "gauge1"},
596                         {Name: "gauge2", Help: "gauge2"},
597                 },
598                 []string{"host"},
599                 "SUBSYSTEM")
600
601         stats:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vecgrp)
602         stats["gauge1"].Inc()
603 */
604
605 // Deprecated: Use RegisterLabeledGauge
606 func (m *Metrics) RegisterGaugeVec(opts CounterOpts, labelNames []string, subsytem string) GaugeVec {
607         globalLock.Lock()
608         defer globalLock.Unlock()
609         opts.Namespace = m.Namespace
610         opts.Subsystem = subsytem
611         vecid := m.getFullName(prometheus.Opts(opts), []string{})
612         if _, ok := cache_allgauges[vecid]; ok {
613                 Logger.Warn("Register new gauge vector with opts: %v labelNames: %v, name conflicts existing counter", opts, labelNames)
614                 return GaugeVec{}
615         }
616         if _, ok := cache_allgaugevects[vecid]; !ok {
617                 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
618                 entry := GaugeVec{}
619                 entry.Opts = opts
620                 entry.Labels = labelNames
621                 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
622                 cache_allgaugevects[vecid] = entry
623         }
624         entry := cache_allgaugevects[vecid]
625         if strSliceCompare(entry.Labels, labelNames) == false {
626                 Logger.Warn("id:%s cached gauge vec labels dont match %v != %v", vecid, entry.Labels, labelNames)
627                 return GaugeVec{}
628         }
629         return entry
630 }
631
632 // Deprecated: Use RegisterLabeledGaugeGroup
633 func (m *Metrics) RegisterGaugeVecGroup(optsgroup []CounterOpts, labelNames []string, subsytem string) map[string]GaugeVec {
634         c := make(map[string]GaugeVec)
635         for _, opts := range optsgroup {
636                 ret := m.RegisterGaugeVec(opts, labelNames, subsytem)
637                 if ret.Vec != nil {
638                         c[opts.Name] = ret
639                 }
640
641         }
642         return c
643 }
644
645 // Deprecated: Use RegisterLabeledGauge
646 func (m *Metrics) GetGaugeFromVect(labelValues []string, vec GaugeVec) Gauge {
647         globalLock.Lock()
648         defer globalLock.Unlock()
649         valid := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
650         if _, ok := cache_allgauges[valid]; !ok {
651                 Logger.Debug("Register new gauge from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
652                 cache_allgauges[valid] = vec.Vec.WithLabelValues(labelValues...)
653         }
654         return cache_allgauges[valid]
655 }
656
657 // Deprecated: Use RegisterLabeledGaugeGroup
658 func (m *Metrics) GetGaugeGroupFromVects(labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
659         c := make(map[string]Gauge)
660         for _, vect := range vects {
661                 for name, vec := range vect {
662                         c[name] = m.GetGaugeFromVect(labelValues, vec)
663                 }
664         }
665         return c
666 }
667
668 // Deprecated: Use RegisterLabeledGaugeGroup
669 func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
670         c := make(map[string]Gauge)
671         for _, vect := range vects {
672                 for name, vec := range vect {
673                         c[prefix+name] = m.GetGaugeFromVect(labelValues, vec)
674                 }
675         }
676         return c
677 }