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