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"
304 namespace = "ricxapp"
307 Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
309 // Expose 'metrics' endpoint with standard golang metrics used by prometheus
310 r.Handle(url, promhttp.Handler())
312 return &Metrics{Namespace: namespace}
318 func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
320 for _, lbl := range labels {
321 if len(labelname) == 0 {
324 labelname += "_" + lbl
327 return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
333 func (m *Metrics) RegisterCounter(opts CounterOpts, subsytem string) Counter {
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)
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))
347 return cache_allcounters[id]
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)
364 func (m *Metrics) RegisterLabeledCounter(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Counter {
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)
374 if _, ok := cache_allcountervects[vecid]; !ok {
375 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
376 entry := CounterVec{}
378 entry.Labels = labelNames
379 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
380 cache_allcountervects[vecid] = entry
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)
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...)
392 return cache_allcounters[valid]
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)
409 func (m *Metrics) RegisterGauge(opts CounterOpts, subsytem string) Gauge {
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)
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))
423 return cache_allgauges[id]
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)
440 func (m *Metrics) RegisterLabeledGauge(opts CounterOpts, labelNames []string, labelValues []string, subsytem string) Gauge {
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)
450 if _, ok := cache_allgaugevects[vecid]; !ok {
451 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
454 entry.Labels = labelNames
455 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
456 cache_allgaugevects[vecid] = entry
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)
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...)
468 return cache_allgauges[valid]
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)
483 * Handling counter vectors
488 vec := Metric.RegisterCounterVec(
489 CounterOpts{Name: "counter0", Help: "counter0"},
493 stat:=Metric.GetCounterFromVect([]string{"localhost:8888"},vec)
497 vec := Metric.RegisterCounterVecGroup(
499 {Name: "counter1", Help: "counter1"},
500 {Name: "counter2", Help: "counter2"},
505 stats:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
506 stats["counter1"].Inc()
509 // Deprecated: Use RegisterLabeledCounter
510 func (m *Metrics) RegisterCounterVec(opts CounterOpts, labelNames []string, subsytem string) CounterVec {
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)
520 if _, ok := cache_allcountervects[vecid]; !ok {
521 Logger.Debug("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
522 entry := CounterVec{}
524 entry.Labels = labelNames
525 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
526 cache_allcountervects[vecid] = entry
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)
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)
548 // Deprecated: Use RegisterLabeledCounter
549 func (m *Metrics) GetCounterFromVect(labelValues []string, vec CounterVec) (c Counter) {
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...)
557 return cache_allcounters[valid]
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)
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)
583 * Handling gauge vectors
588 vec := Metric.RegisterGaugeVec(
589 CounterOpts{Name: "gauge0", Help: "gauge0"},
593 stat:=Metric.GetGaugeFromVect([]string{"localhost:8888"},vec)
597 vecgrp := Metric.RegisterGaugeVecGroup(
599 {Name: "gauge1", Help: "gauge1"},
600 {Name: "gauge2", Help: "gauge2"},
605 stats:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vecgrp)
606 stats["gauge1"].Inc()
609 // Deprecated: Use RegisterLabeledGauge
610 func (m *Metrics) RegisterGaugeVec(opts CounterOpts, labelNames []string, subsytem string) GaugeVec {
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)
620 if _, ok := cache_allgaugevects[vecid]; !ok {
621 Logger.Debug("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
624 entry.Labels = labelNames
625 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
626 cache_allgaugevects[vecid] = entry
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)
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)
649 // Deprecated: Use RegisterLabeledGauge
650 func (m *Metrics) GetGaugeFromVect(labelValues []string, vec GaugeVec) Gauge {
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...)
658 return cache_allgauges[valid]
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)
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)