73a9b62179f887cde2c1c1ec05daf07b81a2b066
[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         "github.com/gorilla/mux"
24         "github.com/prometheus/client_golang/prometheus"
25         "github.com/prometheus/client_golang/prometheus/promauto"
26         "github.com/prometheus/client_golang/prometheus/promhttp"
27         "sync"
28 )
29
30 //-----------------------------------------------------------------------------
31 // Alias
32 //-----------------------------------------------------------------------------
33 type CounterOpts prometheus.Opts
34 type Counter prometheus.Counter
35 type Gauge prometheus.Gauge
36
37 //-----------------------------------------------------------------------------
38 //
39 //-----------------------------------------------------------------------------
40
41 type MetricGroupsCache struct {
42         Counters map[string]Counter
43         Gauges   map[string]Gauge
44 }
45
46 func (met *MetricGroupsCache) CInc(metric string) {
47         met.Counters[metric].Inc()
48 }
49
50 func (met *MetricGroupsCache) CAdd(metric string, val float64) {
51         met.Counters[metric].Add(val)
52 }
53
54 func (met *MetricGroupsCache) GSet(metric string, val float64) {
55         met.Gauges[metric].Set(val)
56 }
57
58 //-----------------------------------------------------------------------------
59 //
60 //-----------------------------------------------------------------------------
61 type Metrics struct {
62         lock                 sync.Mutex
63         Namespace            string
64         MetricGroupsCacheMap map[string]*MetricGroupsCache
65 }
66
67 func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
68         if url == "" {
69                 url = "/ric/v1/metrics"
70         }
71         if namespace == "" {
72                 namespace = "ricxapp"
73         }
74
75         Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
76
77         // Expose 'metrics' endpoint with standard golang metrics used by prometheus
78         r.Handle(url, promhttp.Handler())
79
80         return &Metrics{Namespace: namespace, MetricGroupsCacheMap: make(map[string]*MetricGroupsCache)}
81 }
82
83 /*
84  * Handling counters
85  */
86 func (m *Metrics) registerCounter(opts CounterOpts) Counter {
87         Logger.Info("Register new counter with opts: %v", opts)
88         return promauto.NewCounter(prometheus.CounterOpts(opts))
89 }
90
91 func (m *Metrics) RegisterCounterGroup(opts []CounterOpts, subsytem string) (c map[string]Counter) {
92         c = make(map[string]Counter)
93         for _, opt := range opts {
94                 opt.Namespace = m.Namespace
95                 opt.Subsystem = subsytem
96                 c[opt.Name] = m.registerCounter(opt)
97         }
98
99         return
100 }
101
102 /*
103  * Handling gauges
104  */
105 func (m *Metrics) registerGauge(opts CounterOpts) Gauge {
106         Logger.Info("Register new gauge with opts: %v", opts)
107         return promauto.NewGauge(prometheus.GaugeOpts(opts))
108 }
109
110 func (m *Metrics) RegisterGaugeGroup(opts []CounterOpts, subsytem string) (c map[string]Gauge) {
111         c = make(map[string]Gauge)
112         for _, opt := range opts {
113                 opt.Namespace = m.Namespace
114                 opt.Subsystem = subsytem
115                 c[opt.Name] = m.registerGauge(opt)
116         }
117
118         return
119 }
120
121 /*
122  * Handling counter vectors
123  *
124  * Example:
125
126         vec := Metric.RegisterCounterVecGroup(
127                 []CounterOpts{
128                         {Name: "counter1", Help: "counter1"},
129                         {Name: "counter2", Help: "counter2"},
130                 },
131                 []string{"host"},
132                 "SUBSYSTEM")
133
134         stat:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
135
136 */
137 type CounterVec struct {
138         Vec  *prometheus.CounterVec
139         Opts CounterOpts
140 }
141
142 func (m *Metrics) registerCounterVec(opts CounterOpts, labelNames []string) *prometheus.CounterVec {
143         Logger.Info("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
144
145         return promauto.NewCounterVec(prometheus.CounterOpts(opts), labelNames)
146 }
147
148 func (m *Metrics) RegisterCounterVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]CounterVec) {
149         c = make(map[string]CounterVec)
150         for _, opt := range opts {
151                 entry := CounterVec{}
152                 entry.Opts = opt
153                 entry.Opts.Namespace = m.Namespace
154                 entry.Opts.Subsystem = subsytem
155                 entry.Vec = m.registerCounterVec(entry.Opts, labelNames)
156                 c[opt.Name] = entry
157         }
158         return
159 }
160
161 func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
162         c = make(map[string]Counter)
163         for _, vec := range vects {
164                 for name, opt := range vec {
165                         c[prefix+name] = opt.Vec.WithLabelValues(labels...)
166                         Logger.Info("Register new counter for vector with opts: %v labels: %v", opt.Opts, labels)
167                 }
168         }
169         return
170 }
171
172 func (m *Metrics) GetCounterGroupFromVects(labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
173         return m.GetCounterGroupFromVectsWithPrefix("", labels, vects...)
174 }
175
176 /*
177  * Handling gauge vectors
178  *
179  * Example:
180
181         vec := Metric.RegisterGaugeVecGroup(
182                 []CounterOpts{
183                         {Name: "gauge1", Help: "gauge1"},
184                         {Name: "gauge2", Help: "gauge2"},
185                 },
186                 []string{"host"},
187                 "SUBSYSTEM")
188
189         stat:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vec)
190
191 */
192 type GaugeVec struct {
193         Vec  *prometheus.GaugeVec
194         Opts CounterOpts
195 }
196
197 func (m *Metrics) registerGaugeVec(opts CounterOpts, labelNames []string) *prometheus.GaugeVec {
198         Logger.Info("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
199
200         return promauto.NewGaugeVec(prometheus.GaugeOpts(opts), labelNames)
201 }
202
203 func (m *Metrics) RegisterGaugeVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]GaugeVec) {
204         c = make(map[string]GaugeVec)
205         for _, opt := range opts {
206                 entry := GaugeVec{}
207                 entry.Opts = opt
208                 entry.Opts.Namespace = m.Namespace
209                 entry.Opts.Subsystem = subsytem
210                 entry.Vec = m.registerGaugeVec(entry.Opts, labelNames)
211                 c[opt.Name] = entry
212
213         }
214         return
215 }
216
217 func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
218         c = make(map[string]Gauge)
219         for _, vec := range vects {
220                 for name, opt := range vec {
221                         c[prefix+name] = opt.Vec.WithLabelValues(labels...)
222                         Logger.Info("Register new gauge for vector with opts: %v labels: %v", opt.Opts, labels)
223                 }
224         }
225         return
226 }
227
228 func (m *Metrics) GetGaugeGroupFromVects(labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
229         return m.GetGaugeGroupFromVectsWithPrefix("", labels, vects...)
230
231 }
232
233 /*
234  *
235  */
236 func (m *Metrics) CombineCounterGroups(srcs ...map[string]Counter) map[string]Counter {
237         trg := make(map[string]Counter)
238         for _, src := range srcs {
239                 for k, v := range src {
240                         trg[k] = v
241                 }
242         }
243         return trg
244 }
245
246 func (m *Metrics) CombineGaugeGroups(srcs ...map[string]Gauge) map[string]Gauge {
247         trg := make(map[string]Gauge)
248         for _, src := range srcs {
249                 for k, v := range src {
250                         trg[k] = v
251                 }
252         }
253         return trg
254 }
255
256 /*
257  *
258  */
259 func (m *Metrics) GroupCacheGet(id string) *MetricGroupsCache {
260         m.lock.Lock()
261         defer m.lock.Unlock()
262         entry, ok := m.MetricGroupsCacheMap[id]
263         if ok == false {
264                 return nil
265         }
266         return entry
267 }
268
269 func (m *Metrics) GroupCacheAddCounters(id string, vals map[string]Counter) {
270         m.lock.Lock()
271         defer m.lock.Unlock()
272         entry, ok := m.MetricGroupsCacheMap[id]
273         if ok == false {
274                 entry = &MetricGroupsCache{}
275                 m.MetricGroupsCacheMap[id] = entry
276         }
277         m.MetricGroupsCacheMap[id].Counters = m.CombineCounterGroups(m.MetricGroupsCacheMap[id].Counters, vals)
278 }
279
280 func (m *Metrics) GroupCacheAddGauges(id string, vals map[string]Gauge) {
281         m.lock.Lock()
282         defer m.lock.Unlock()
283         entry, ok := m.MetricGroupsCacheMap[id]
284         if ok == false {
285                 entry = &MetricGroupsCache{}
286                 m.MetricGroupsCacheMap[id] = entry
287         }
288         m.MetricGroupsCacheMap[id].Gauges = m.CombineGaugeGroups(m.MetricGroupsCacheMap[id].Gauges, vals)
289 }