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 type CounterOpts prometheus.Opts
35 type Counter prometheus.Counter
36 type Gauge prometheus.Gauge
38 type CounterVec struct {
39 Vec *prometheus.CounterVec
44 type GaugeVec struct {
45 Vec *prometheus.GaugeVec
50 func strSliceCompare(a, b []string) bool {
62 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
66 type MetricGroupsCache struct {
67 sync.RWMutex //This is for map locking
68 counters map[string]Counter
69 gauges map[string]Gauge
72 func (met *MetricGroupsCache) CIs(metric string) bool {
75 _, ok := met.counters[metric]
79 func (met *MetricGroupsCache) CGet(metric string) Counter {
82 return met.counters[metric]
85 func (met *MetricGroupsCache) CInc(metric string) {
88 met.counters[metric].Inc()
91 func (met *MetricGroupsCache) CAdd(metric string, val float64) {
94 met.counters[metric].Add(val)
97 func (met *MetricGroupsCache) GIs(metric string) bool {
100 _, ok := met.gauges[metric]
104 func (met *MetricGroupsCache) GGet(metric string) Gauge {
107 return met.gauges[metric]
110 func (met *MetricGroupsCache) GSet(metric string, val float64) {
113 met.gauges[metric].Set(val)
116 func (met *MetricGroupsCache) GAdd(metric string, val float64) {
119 met.gauges[metric].Add(val)
122 func (met *MetricGroupsCache) GInc(metric string) {
125 met.gauges[metric].Inc()
128 func (met *MetricGroupsCache) GDec(metric string) {
131 met.gauges[metric].Dec()
134 func (met *MetricGroupsCache) CombineCounterGroupsWithPrefix(prefix string, srcs ...map[string]Counter) {
137 for _, src := range srcs {
138 for k, v := range src {
139 met.counters[prefix+k] = v
144 func (met *MetricGroupsCache) CombineCounterGroups(srcs ...map[string]Counter) {
147 for _, src := range srcs {
148 for k, v := range src {
154 func (met *MetricGroupsCache) CombineGaugeGroupsWithPrefix(prefix string, srcs ...map[string]Gauge) {
157 for _, src := range srcs {
158 for k, v := range src {
159 met.gauges[prefix+k] = v
164 func (met *MetricGroupsCache) CombineGaugeGroups(srcs ...map[string]Gauge) {
167 for _, src := range srcs {
168 for k, v := range src {
174 func NewMetricGroupsCache() *MetricGroupsCache {
175 entry := &MetricGroupsCache{}
176 entry.counters = make(map[string]Counter)
177 entry.gauges = make(map[string]Gauge)
181 //-----------------------------------------------------------------------------
182 // All counters/gauges registered via Metrics instances:
183 // Counter names are build from: namespace, subsystem, metric and possible labels
184 //-----------------------------------------------------------------------------
185 var globalLock sync.Mutex
186 var cache_allcounters map[string]Counter
187 var cache_allgauges map[string]Gauge
188 var cache_allcountervects map[string]CounterVec
189 var cache_allgaugevects map[string]GaugeVec
192 cache_allcounters = make(map[string]Counter)
193 cache_allgauges = make(map[string]Gauge)
194 cache_allcountervects = make(map[string]CounterVec)
195 cache_allgaugevects = make(map[string]GaugeVec)
198 //-----------------------------------------------------------------------------
200 //-----------------------------------------------------------------------------
201 type Metrics struct {
205 func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
207 url = "/ric/v1/metrics"
210 namespace = "ricxapp"
213 Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
215 // Expose 'metrics' endpoint with standard golang metrics used by prometheus
216 r.Handle(url, promhttp.Handler())
218 return &Metrics{Namespace: namespace}
224 func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
226 for _, lbl := range labels {
227 if len(labelname) == 0 {
230 labelname += "_" + lbl
233 return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
239 func (m *Metrics) RegisterCounter(opts CounterOpts, subsytem string) Counter {
241 defer globalLock.Unlock()
242 opts.Namespace = m.Namespace
243 opts.Subsystem = subsytem
244 id := m.getFullName(prometheus.Opts(opts), []string{})
245 if _, ok := cache_allcounters[id]; !ok {
246 Logger.Info("Register new counter with opts: %v", opts)
247 cache_allcounters[id] = promauto.NewCounter(prometheus.CounterOpts(opts))
249 return cache_allcounters[id]
252 func (m *Metrics) RegisterCounterGroup(optsgroup []CounterOpts, subsytem string) map[string]Counter {
253 c := make(map[string]Counter)
254 for _, opts := range optsgroup {
255 c[opts.Name] = m.RegisterCounter(opts, subsytem)
263 func (m *Metrics) RegisterGauge(opts CounterOpts, subsytem string) Gauge {
265 defer globalLock.Unlock()
266 opts.Namespace = m.Namespace
267 opts.Subsystem = subsytem
268 id := m.getFullName(prometheus.Opts(opts), []string{})
269 if _, ok := cache_allgauges[id]; !ok {
270 Logger.Info("Register new gauge with opts: %v", opts)
271 cache_allgauges[id] = promauto.NewGauge(prometheus.GaugeOpts(opts))
273 return cache_allgauges[id]
276 func (m *Metrics) RegisterGaugeGroup(optsgroup []CounterOpts, subsytem string) map[string]Gauge {
277 c := make(map[string]Gauge)
278 for _, opts := range optsgroup {
279 c[opts.Name] = m.RegisterGauge(opts, subsytem)
285 * Handling counter vectors
290 vec := Metric.RegisterCounterVec(
291 CounterOpts{Name: "counter0", Help: "counter0"},
295 stat:=Metric.GetCounterFromVect([]string{"localhost:8888"},vec)
299 vec := Metric.RegisterCounterVecGroup(
301 {Name: "counter1", Help: "counter1"},
302 {Name: "counter2", Help: "counter2"},
307 stats:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
308 stats["counter1"].Inc()
311 func (m *Metrics) RegisterCounterVec(opts CounterOpts, labelNames []string, subsytem string) CounterVec {
313 defer globalLock.Unlock()
314 opts.Namespace = m.Namespace
315 opts.Subsystem = subsytem
316 id := m.getFullName(prometheus.Opts(opts), []string{})
317 if _, ok := cache_allcountervects[id]; !ok {
318 Logger.Info("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
319 entry := CounterVec{}
321 entry.Labels = labelNames
322 entry.Vec = promauto.NewCounterVec(prometheus.CounterOpts(entry.Opts), entry.Labels)
323 cache_allcountervects[id] = entry
325 entry := cache_allcountervects[id]
326 if strSliceCompare(entry.Labels, labelNames) == false {
327 Logger.Warn("id:%s cached counter vec labels dont match %v != %v", id, entry.Labels, labelNames)
332 func (m *Metrics) RegisterCounterVecGroup(optsgroup []CounterOpts, labelNames []string, subsytem string) map[string]CounterVec {
333 c := make(map[string]CounterVec)
334 for _, opts := range optsgroup {
335 c[opts.Name] = m.RegisterCounterVec(opts, labelNames, subsytem)
340 func (m *Metrics) GetCounterFromVect(labelValues []string, vec CounterVec) (c Counter) {
342 defer globalLock.Unlock()
343 id := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
344 if _, ok := cache_allcounters[id]; !ok {
345 Logger.Info("Register new counter from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
346 cache_allcounters[id] = vec.Vec.WithLabelValues(labelValues...)
348 return cache_allcounters[id]
351 func (m *Metrics) GetCounterGroupFromVects(labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
352 c := make(map[string]Counter)
353 for _, vect := range vects {
354 for name, vec := range vect {
355 c[name] = m.GetCounterFromVect(labelValues, vec)
361 func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]CounterVec) map[string]Counter {
362 c := make(map[string]Counter)
363 for _, vect := range vects {
364 for name, vec := range vect {
365 c[prefix+name] = m.GetCounterFromVect(labelValues, vec)
372 * Handling gauge vectors
377 vec := Metric.RegisterGaugeVec(
378 CounterOpts{Name: "gauge0", Help: "gauge0"},
382 stat:=Metric.GetGaugeFromVect([]string{"localhost:8888"},vec)
386 vecgrp := Metric.RegisterGaugeVecGroup(
388 {Name: "gauge1", Help: "gauge1"},
389 {Name: "gauge2", Help: "gauge2"},
394 stats:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vecgrp)
395 stats["gauge1"].Inc()
398 func (m *Metrics) RegisterGaugeVec(opt CounterOpts, labelNames []string, subsytem string) GaugeVec {
400 defer globalLock.Unlock()
401 opt.Namespace = m.Namespace
402 opt.Subsystem = subsytem
403 id := m.getFullName(prometheus.Opts(opt), []string{})
404 if _, ok := cache_allgaugevects[id]; !ok {
405 Logger.Info("Register new gauge vector with opt: %v labelNames: %v", opt, labelNames)
408 entry.Labels = labelNames
409 entry.Vec = promauto.NewGaugeVec(prometheus.GaugeOpts(entry.Opts), entry.Labels)
410 cache_allgaugevects[id] = entry
412 entry := cache_allgaugevects[id]
413 if strSliceCompare(entry.Labels, labelNames) == false {
414 Logger.Warn("id:%s cached gauge vec labels dont match %v != %v", id, entry.Labels, labelNames)
419 func (m *Metrics) RegisterGaugeVecGroup(opts []CounterOpts, labelNames []string, subsytem string) map[string]GaugeVec {
420 c := make(map[string]GaugeVec)
421 for _, opt := range opts {
422 c[opt.Name] = m.RegisterGaugeVec(opt, labelNames, subsytem)
427 func (m *Metrics) GetGaugeFromVect(labelValues []string, vec GaugeVec) Gauge {
429 defer globalLock.Unlock()
430 id := m.getFullName(prometheus.Opts(vec.Opts), labelValues)
431 if _, ok := cache_allgauges[id]; !ok {
432 Logger.Info("Register new gauge from vector with opts: %v labelValues: %v", vec.Opts, labelValues)
433 cache_allgauges[id] = vec.Vec.WithLabelValues(labelValues...)
435 return cache_allgauges[id]
438 func (m *Metrics) GetGaugeGroupFromVects(labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
439 c := make(map[string]Gauge)
440 for _, vect := range vects {
441 for name, vec := range vect {
442 c[name] = m.GetGaugeFromVect(labelValues, vec)
448 func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labelValues []string, vects ...map[string]GaugeVec) map[string]Gauge {
449 c := make(map[string]Gauge)
450 for _, vect := range vects {
451 for name, vec := range vect {
452 c[prefix+name] = m.GetGaugeFromVect(labelValues, vec)