2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
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
10 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
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"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
34 func strSliceCompare(a, b []string) bool {
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
49 type CounterOpts prometheus.Opts
50 type Counter prometheus.Counter
51 type Gauge prometheus.Gauge
53 type CounterVec struct {
54 Vec *prometheus.CounterVec
59 type GaugeVec struct {
60 Vec *prometheus.GaugeVec
65 //-----------------------------------------------------------------------------
67 //-----------------------------------------------------------------------------
68 type MetricGroupsCacheCounterRegisterer interface {
69 RegisterCounter(CounterOpts) Counter
72 type MetricGroupsCacheCounterRegistererFunc func(CounterOpts) Counter
74 func (fn MetricGroupsCacheCounterRegistererFunc) RegisterCounter(copts CounterOpts) Counter {
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
81 type MetricGroupsCacheGaugeRegisterer interface {
82 RegisterGauge(CounterOpts) Gauge
85 type MetricGroupsCacheGaugeRegistererFunc func(CounterOpts) Gauge
87 func (fn MetricGroupsCacheGaugeRegistererFunc) RegisterGauge(copts CounterOpts) Gauge {
91 //-----------------------------------------------------------------------------
93 //-----------------------------------------------------------------------------
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
103 func (met *MetricGroupsCache) Registerer(regcnt MetricGroupsCacheCounterRegisterer, reggau MetricGroupsCacheGaugeRegisterer) {
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
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
125 func (met *MetricGroupsCache) CIs(metric string) bool {
128 _, ok := met.counters[metric]
132 func (met *MetricGroupsCache) CGet(metric string) Counter {
135 cntr, ok := met.counters[metric]
137 cntr = met.cReg(metric)
142 func (met *MetricGroupsCache) CInc(metric string) {
145 cntr, ok := met.counters[metric]
147 cntr = met.cReg(metric)
152 func (met *MetricGroupsCache) CAdd(metric string, val float64) {
155 cntr, ok := met.counters[metric]
157 cntr = met.cReg(metric)
162 func (met *MetricGroupsCache) GIs(metric string) bool {
165 _, ok := met.gauges[metric]
169 func (met *MetricGroupsCache) GGet(metric string) Gauge {
172 gaug, ok := met.gauges[metric]
174 gaug = met.gReg(metric)
179 func (met *MetricGroupsCache) GSet(metric string, val float64) {
182 gaug, ok := met.gauges[metric]
184 gaug = met.gReg(metric)
189 func (met *MetricGroupsCache) GAdd(metric string, val float64) {
192 gaug, ok := met.gauges[metric]
194 gaug = met.gReg(metric)
199 func (met *MetricGroupsCache) GInc(metric string) {
202 gaug, ok := met.gauges[metric]
204 gaug = met.gReg(metric)
209 func (met *MetricGroupsCache) GDec(metric string) {
212 gaug, ok := met.gauges[metric]
214 gaug = met.gReg(metric)
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
227 func (met *MetricGroupsCache) CombineCounterGroupsWithPrefix(prefix string, srcs ...map[string]Counter) {
230 met.combineCounterGroupsWithPrefix(prefix, srcs...)
233 func (met *MetricGroupsCache) CombineCounterGroups(srcs ...map[string]Counter) {
236 met.combineCounterGroupsWithPrefix("", srcs...)
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
247 func (met *MetricGroupsCache) CombineGaugeGroupsWithPrefix(prefix string, srcs ...map[string]Gauge) {
250 met.combineGaugeGroupsWithPrefix(prefix, srcs...)
253 func (met *MetricGroupsCache) CombineGaugeGroups(srcs ...map[string]Gauge) {
256 met.combineGaugeGroupsWithPrefix("", srcs...)
259 func NewMetricGroupsCache() *MetricGroupsCache {
260 entry := &MetricGroupsCache{}
261 entry.counters = make(map[string]Counter)
262 entry.gauges = make(map[string]Gauge)
268 func NewMetricGroupsCacheWithRegisterers(regcnt MetricGroupsCacheCounterRegisterer, reggau MetricGroupsCacheGaugeRegisterer) *MetricGroupsCache {
269 entry := NewMetricGroupsCache()
270 entry.regcnt = regcnt
271 entry.reggau = reggau
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
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)
292 //-----------------------------------------------------------------------------
294 //-----------------------------------------------------------------------------
295 type Metrics struct {
299 func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
301 url = "/ric/v1/metrics"
303 Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
305 // Expose 'metrics' endpoint with standard golang metrics used by prometheus
306 r.Handle(url, promhttp.Handler())
308 return &Metrics{Namespace: namespace}
314 func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
316 for _, lbl := range labels {
317 if len(labelname) == 0 {
320 labelname += "_" + lbl
323 return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
329 func (m *Metrics) RegisterCounter(opts CounterOpts, subsytem string) Counter {
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)
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))
343 return cache_allcounters[id]
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)
360 func (m *Metrics) RegisterLabeledCounter(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Counter {
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)
370 if _, ok := cache_allcountervects[vecid]; !ok {
371 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
372 entry := CounterVec{}
374 entry.Labels = labelNames
375 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
376 cache_allcountervects[vecid] = entry
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)
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...)
388 return cache_allcounters[valid]
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)
405 func (m *Metrics) RegisterGauge(opts CounterOpts, subsytem string) Gauge {
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)
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))
419 return cache_allgauges[id]
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)
436 func (m *Metrics) RegisterLabeledGauge(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Gauge {
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)
446 if _, ok := cache_allgaugevects[vecid]; !ok {
447 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
450 entry.Labels = labelNames
451 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
452 cache_allgaugevects[vecid] = entry
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)
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...)
464 return cache_allgauges[valid]
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)
479 * Handling counter vectors
484 vec := Metric.RegisterCounterVec(
485 CounterOpts{Name: "counter0", Help: "counter0"},
489 stat:=Metric.GetCounterFromVect([]string{"localhost:8888"},vec)
493 vec := Metric.RegisterCounterVecGroup(
495 {Name: "counter1", Help: "counter1"},
496 {Name: "counter2", Help: "counter2"},
501 stats:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
502 stats["counter1"].Inc()
505 // Deprecated: Use RegisterLabeledCounter
506 func (m *Metrics) RegisterCounterVec(opts CounterOpts, labelNames []string, subsytem string) CounterVec {
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)
516 if _, ok := cache_allcountervects[vecid]; !ok {
517 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
518 entry := CounterVec{}
520 entry.Labels = labelNames
521 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
522 cache_allcountervects[vecid] = entry
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)
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)
544 // Deprecated: Use RegisterLabeledCounter
545 func (m *Metrics) GetCounterFromVect(labelValues []string, vec CounterVec) (c Counter) {
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...)
553 return cache_allcounters[valid]
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)
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)
579 * Handling gauge vectors
584 vec := Metric.RegisterGaugeVec(
585 CounterOpts{Name: "gauge0", Help: "gauge0"},
589 stat:=Metric.GetGaugeFromVect([]string{"localhost:8888"},vec)
593 vecgrp := Metric.RegisterGaugeVecGroup(
595 {Name: "gauge1", Help: "gauge1"},
596 {Name: "gauge2", Help: "gauge2"},
601 stats:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vecgrp)
602 stats["gauge1"].Inc()
605 // Deprecated: Use RegisterLabeledGauge
606 func (m *Metrics) RegisterGaugeVec(opts CounterOpts, labelNames []string, subsytem string) GaugeVec {
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)
616 if _, ok := cache_allgaugevects[vecid]; !ok {
617 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
620 entry.Labels = labelNames
621 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
622 cache_allgaugevects[vecid] = entry
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)
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)
645 // Deprecated: Use RegisterLabeledGauge
646 func (m *Metrics) GetGaugeFromVect(labelValues []string, vec GaugeVec) Gauge {
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...)
654 return cache_allgauges[valid]
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)
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)