blob: 40adbcde29862b8e952e503020dd0720eb2ba22e [file] [log] [blame]
Mohamed Abukar2e78e422019-06-02 11:45:52 +03001/*
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
20package xapp
21
22import (
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020023 "fmt"
Mohamed Abukar2e78e422019-06-02 11:45:52 +030024 "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"
Juha Hyttinen64924382020-10-08 14:06:57 +030028 "sync"
Mohamed Abukar2e78e422019-06-02 11:45:52 +030029)
30
Juha Hyttinen90f6dd42020-05-08 12:17:05 +030031//-----------------------------------------------------------------------------
Mohamed Abukar2e78e422019-06-02 11:45:52 +030032// Alias
Juha Hyttinen90f6dd42020-05-08 12:17:05 +030033//-----------------------------------------------------------------------------
Juha Hyttinenf619d032020-05-07 12:42:26 +030034type CounterOpts prometheus.Opts
Mohamed Abukar2e78e422019-06-02 11:45:52 +030035type Counter prometheus.Counter
36type Gauge prometheus.Gauge
37
Juha Hyttinen90f6dd42020-05-08 12:17:05 +030038//-----------------------------------------------------------------------------
39//
40//-----------------------------------------------------------------------------
41
42type MetricGroupsCache struct {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020043 sync.RWMutex //This is for map locking
44 counters map[string]Counter
45 gauges map[string]Gauge
46}
47
48func (met *MetricGroupsCache) CIs(metric string) bool {
49 met.RLock()
50 defer met.RUnlock()
51 _, ok := met.counters[metric]
52 return ok
Juha Hyttinen90f6dd42020-05-08 12:17:05 +030053}
54
Juha Hyttinenf1703602020-10-30 12:31:01 +020055func (met *MetricGroupsCache) CGet(metric string) Counter {
56 met.RLock()
57 defer met.RUnlock()
58 return met.counters[metric]
59}
60
Juha Hyttinen622bae32020-08-10 08:20:22 +030061func (met *MetricGroupsCache) CInc(metric string) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020062 met.RLock()
63 defer met.RUnlock()
64 met.counters[metric].Inc()
Juha Hyttinen622bae32020-08-10 08:20:22 +030065}
66
67func (met *MetricGroupsCache) CAdd(metric string, val float64) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020068 met.RLock()
69 defer met.RUnlock()
70 met.counters[metric].Add(val)
71}
72
73func (met *MetricGroupsCache) GIs(metric string) bool {
74 met.RLock()
75 defer met.RUnlock()
76 _, ok := met.gauges[metric]
77 return ok
Juha Hyttinen622bae32020-08-10 08:20:22 +030078}
79
Juha Hyttinenf1703602020-10-30 12:31:01 +020080func (met *MetricGroupsCache) GGet(metric string) Gauge {
81 met.RLock()
82 defer met.RUnlock()
83 return met.gauges[metric]
84}
85
Juha Hyttinen622bae32020-08-10 08:20:22 +030086func (met *MetricGroupsCache) GSet(metric string, val float64) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020087 met.RLock()
88 defer met.RUnlock()
89 met.gauges[metric].Set(val)
90}
91
Juha Hyttinena5435ca2021-06-23 10:54:57 +030092func (met *MetricGroupsCache) GAdd(metric string, val float64) {
93 met.RLock()
94 defer met.RUnlock()
95 met.gauges[metric].Add(val)
96}
97
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020098func (met *MetricGroupsCache) GInc(metric string) {
99 met.RLock()
100 defer met.RUnlock()
101 met.gauges[metric].Inc()
102}
103
104func (met *MetricGroupsCache) GDec(metric string) {
105 met.RLock()
106 defer met.RUnlock()
107 met.gauges[metric].Dec()
108}
109
110func (met *MetricGroupsCache) CombineCounterGroups(srcs ...map[string]Counter) {
111 met.Lock()
112 defer met.Unlock()
113 for _, src := range srcs {
114 for k, v := range src {
115 met.counters[k] = v
116 }
117 }
118}
119
120func (met *MetricGroupsCache) CombineGaugeGroups(srcs ...map[string]Gauge) {
121 met.Lock()
122 defer met.Unlock()
123 for _, src := range srcs {
124 for k, v := range src {
125 met.gauges[k] = v
126 }
127 }
128}
129
130func NewMetricGroupsCache() *MetricGroupsCache {
131 entry := &MetricGroupsCache{}
132 entry.counters = make(map[string]Counter)
133 entry.gauges = make(map[string]Gauge)
134 return entry
135}
136
137//-----------------------------------------------------------------------------
138// All counters/gauges registered via Metrics instances:
139// Counter names are build from: namespace, subsystem, metric and possible labels
140//-----------------------------------------------------------------------------
141var globalLock sync.Mutex
142var cache_allcounters map[string]Counter
143var cache_allgauges map[string]Gauge
144
145func init() {
146 cache_allcounters = make(map[string]Counter)
147 cache_allgauges = make(map[string]Gauge)
Juha Hyttinen622bae32020-08-10 08:20:22 +0300148}
149
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300150//-----------------------------------------------------------------------------
151//
152//-----------------------------------------------------------------------------
153type Metrics struct {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200154 Namespace string
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300155}
156
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300157func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
158 if url == "" {
159 url = "/ric/v1/metrics"
160 }
161 if namespace == "" {
162 namespace = "ricxapp"
163 }
164
165 Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
166
167 // Expose 'metrics' endpoint with standard golang metrics used by prometheus
168 r.Handle(url, promhttp.Handler())
169
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200170 return &Metrics{Namespace: namespace}
171}
172
173/*
174 * Helpers
175 */
176func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
177 labelname := ""
178 for _, lbl := range labels {
179 if len(labelname) == 0 {
180 labelname += lbl
181 } else {
182 labelname += "_" + lbl
183 }
184 }
185 return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300186}
187
Juha Hyttinenf619d032020-05-07 12:42:26 +0300188/*
189 * Handling counters
190 */
191func (m *Metrics) registerCounter(opts CounterOpts) Counter {
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300192 Logger.Info("Register new counter with opts: %v", opts)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300193 return promauto.NewCounter(prometheus.CounterOpts(opts))
194}
195
196func (m *Metrics) RegisterCounterGroup(opts []CounterOpts, subsytem string) (c map[string]Counter) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200197 globalLock.Lock()
198 defer globalLock.Unlock()
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300199 c = make(map[string]Counter)
200 for _, opt := range opts {
201 opt.Namespace = m.Namespace
202 opt.Subsystem = subsytem
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200203
204 id := m.getFullName(prometheus.Opts(opt), []string{})
205 if _, ok := cache_allcounters[id]; !ok {
206 cache_allcounters[id] = m.registerCounter(opt)
207 }
208
209 c[opt.Name] = cache_allcounters[id]
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300210 }
211
212 return
213}
214
Juha Hyttinenf619d032020-05-07 12:42:26 +0300215/*
216 * Handling gauges
217 */
218func (m *Metrics) registerGauge(opts CounterOpts) Gauge {
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300219 Logger.Info("Register new gauge with opts: %v", opts)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300220 return promauto.NewGauge(prometheus.GaugeOpts(opts))
221}
222
223func (m *Metrics) RegisterGaugeGroup(opts []CounterOpts, subsytem string) (c map[string]Gauge) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200224 globalLock.Lock()
225 defer globalLock.Unlock()
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300226 c = make(map[string]Gauge)
227 for _, opt := range opts {
228 opt.Namespace = m.Namespace
229 opt.Subsystem = subsytem
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200230
231 id := m.getFullName(prometheus.Opts(opt), []string{})
232 if _, ok := cache_allgauges[id]; !ok {
233 cache_allgauges[id] = m.registerGauge(opt)
234 }
235
236 c[opt.Name] = cache_allgauges[id]
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300237 }
238
239 return
240}
Juha Hyttinenf619d032020-05-07 12:42:26 +0300241
242/*
243 * Handling counter vectors
244 *
245 * Example:
246
247 vec := Metric.RegisterCounterVecGroup(
248 []CounterOpts{
249 {Name: "counter1", Help: "counter1"},
250 {Name: "counter2", Help: "counter2"},
251 },
252 []string{"host"},
253 "SUBSYSTEM")
254
255 stat:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
256
257*/
258type CounterVec struct {
259 Vec *prometheus.CounterVec
260 Opts CounterOpts
261}
262
263func (m *Metrics) registerCounterVec(opts CounterOpts, labelNames []string) *prometheus.CounterVec {
264 Logger.Info("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
Juha Hyttinenf619d032020-05-07 12:42:26 +0300265 return promauto.NewCounterVec(prometheus.CounterOpts(opts), labelNames)
266}
267
268func (m *Metrics) RegisterCounterVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]CounterVec) {
269 c = make(map[string]CounterVec)
270 for _, opt := range opts {
271 entry := CounterVec{}
272 entry.Opts = opt
273 entry.Opts.Namespace = m.Namespace
274 entry.Opts.Subsystem = subsytem
275 entry.Vec = m.registerCounterVec(entry.Opts, labelNames)
276 c[opt.Name] = entry
277 }
278 return
279}
280
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300281func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200282 globalLock.Lock()
283 defer globalLock.Unlock()
Juha Hyttinenf619d032020-05-07 12:42:26 +0300284 c = make(map[string]Counter)
285 for _, vec := range vects {
286 for name, opt := range vec {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200287
288 id := m.getFullName(prometheus.Opts(opt.Opts), labels)
289 if _, ok := cache_allcounters[id]; !ok {
290 Logger.Info("Register new counter from vector with opts: %v labels: %v prefix: %s", opt.Opts, labels, prefix)
291 cache_allcounters[id] = opt.Vec.WithLabelValues(labels...)
292 }
293 c[prefix+name] = cache_allcounters[id]
Juha Hyttinenf619d032020-05-07 12:42:26 +0300294 }
295 }
296 return
297}
298
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300299func (m *Metrics) GetCounterGroupFromVects(labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
300 return m.GetCounterGroupFromVectsWithPrefix("", labels, vects...)
301}
302
Juha Hyttinenf619d032020-05-07 12:42:26 +0300303/*
304 * Handling gauge vectors
305 *
306 * Example:
307
308 vec := Metric.RegisterGaugeVecGroup(
309 []CounterOpts{
310 {Name: "gauge1", Help: "gauge1"},
311 {Name: "gauge2", Help: "gauge2"},
312 },
313 []string{"host"},
314 "SUBSYSTEM")
315
316 stat:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vec)
317
318*/
319type GaugeVec struct {
320 Vec *prometheus.GaugeVec
321 Opts CounterOpts
322}
323
324func (m *Metrics) registerGaugeVec(opts CounterOpts, labelNames []string) *prometheus.GaugeVec {
325 Logger.Info("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
Juha Hyttinenf619d032020-05-07 12:42:26 +0300326 return promauto.NewGaugeVec(prometheus.GaugeOpts(opts), labelNames)
327}
328
329func (m *Metrics) RegisterGaugeVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]GaugeVec) {
330 c = make(map[string]GaugeVec)
331 for _, opt := range opts {
332 entry := GaugeVec{}
333 entry.Opts = opt
334 entry.Opts.Namespace = m.Namespace
335 entry.Opts.Subsystem = subsytem
336 entry.Vec = m.registerGaugeVec(entry.Opts, labelNames)
337 c[opt.Name] = entry
338
339 }
340 return
341}
342
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300343func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200344 globalLock.Lock()
345 defer globalLock.Unlock()
Juha Hyttinenf619d032020-05-07 12:42:26 +0300346 c = make(map[string]Gauge)
347 for _, vec := range vects {
348 for name, opt := range vec {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200349
350 id := m.getFullName(prometheus.Opts(opt.Opts), labels)
351 if _, ok := cache_allgauges[id]; !ok {
352 Logger.Info("Register new gauge from vector with opts: %v labels: %v prefix: %s", opt.Opts, labels, prefix)
353 cache_allgauges[id] = opt.Vec.WithLabelValues(labels...)
354 }
355 c[prefix+name] = cache_allgauges[id]
Juha Hyttinenf619d032020-05-07 12:42:26 +0300356 }
357 }
358 return
359}
360
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300361func (m *Metrics) GetGaugeGroupFromVects(labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
362 return m.GetGaugeGroupFromVectsWithPrefix("", labels, vects...)
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300363}