blob: 96f407ca5c9a2442f55380360f86deea02dbffd9 [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 Hyttinen622bae32020-08-10 08:20:22 +030055func (met *MetricGroupsCache) CInc(metric string) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020056 met.RLock()
57 defer met.RUnlock()
58 met.counters[metric].Inc()
Juha Hyttinen622bae32020-08-10 08:20:22 +030059}
60
61func (met *MetricGroupsCache) CAdd(metric string, val float64) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020062 met.RLock()
63 defer met.RUnlock()
64 met.counters[metric].Add(val)
65}
66
67func (met *MetricGroupsCache) GIs(metric string) bool {
68 met.RLock()
69 defer met.RUnlock()
70 _, ok := met.gauges[metric]
71 return ok
Juha Hyttinen622bae32020-08-10 08:20:22 +030072}
73
74func (met *MetricGroupsCache) GSet(metric string, val float64) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +020075 met.RLock()
76 defer met.RUnlock()
77 met.gauges[metric].Set(val)
78}
79
80func (met *MetricGroupsCache) GInc(metric string) {
81 met.RLock()
82 defer met.RUnlock()
83 met.gauges[metric].Inc()
84}
85
86func (met *MetricGroupsCache) GDec(metric string) {
87 met.RLock()
88 defer met.RUnlock()
89 met.gauges[metric].Dec()
90}
91
92func (met *MetricGroupsCache) CombineCounterGroups(srcs ...map[string]Counter) {
93 met.Lock()
94 defer met.Unlock()
95 for _, src := range srcs {
96 for k, v := range src {
97 met.counters[k] = v
98 }
99 }
100}
101
102func (met *MetricGroupsCache) CombineGaugeGroups(srcs ...map[string]Gauge) {
103 met.Lock()
104 defer met.Unlock()
105 for _, src := range srcs {
106 for k, v := range src {
107 met.gauges[k] = v
108 }
109 }
110}
111
112func NewMetricGroupsCache() *MetricGroupsCache {
113 entry := &MetricGroupsCache{}
114 entry.counters = make(map[string]Counter)
115 entry.gauges = make(map[string]Gauge)
116 return entry
117}
118
119//-----------------------------------------------------------------------------
120// All counters/gauges registered via Metrics instances:
121// Counter names are build from: namespace, subsystem, metric and possible labels
122//-----------------------------------------------------------------------------
123var globalLock sync.Mutex
124var cache_allcounters map[string]Counter
125var cache_allgauges map[string]Gauge
126
127func init() {
128 cache_allcounters = make(map[string]Counter)
129 cache_allgauges = make(map[string]Gauge)
Juha Hyttinen622bae32020-08-10 08:20:22 +0300130}
131
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300132//-----------------------------------------------------------------------------
133//
134//-----------------------------------------------------------------------------
135type Metrics struct {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200136 Namespace string
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300137}
138
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300139func NewMetrics(url, namespace string, r *mux.Router) *Metrics {
140 if url == "" {
141 url = "/ric/v1/metrics"
142 }
143 if namespace == "" {
144 namespace = "ricxapp"
145 }
146
147 Logger.Info("Serving metrics on: url=%s namespace=%s", url, namespace)
148
149 // Expose 'metrics' endpoint with standard golang metrics used by prometheus
150 r.Handle(url, promhttp.Handler())
151
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200152 return &Metrics{Namespace: namespace}
153}
154
155/*
156 * Helpers
157 */
158func (m *Metrics) getFullName(opts prometheus.Opts, labels []string) string {
159 labelname := ""
160 for _, lbl := range labels {
161 if len(labelname) == 0 {
162 labelname += lbl
163 } else {
164 labelname += "_" + lbl
165 }
166 }
167 return fmt.Sprintf("%s_%s_%s_%s", opts.Namespace, opts.Subsystem, opts.Name, labelname)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300168}
169
Juha Hyttinenf619d032020-05-07 12:42:26 +0300170/*
171 * Handling counters
172 */
173func (m *Metrics) registerCounter(opts CounterOpts) Counter {
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300174 Logger.Info("Register new counter with opts: %v", opts)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300175 return promauto.NewCounter(prometheus.CounterOpts(opts))
176}
177
178func (m *Metrics) RegisterCounterGroup(opts []CounterOpts, subsytem string) (c map[string]Counter) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200179 globalLock.Lock()
180 defer globalLock.Unlock()
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300181 c = make(map[string]Counter)
182 for _, opt := range opts {
183 opt.Namespace = m.Namespace
184 opt.Subsystem = subsytem
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200185
186 id := m.getFullName(prometheus.Opts(opt), []string{})
187 if _, ok := cache_allcounters[id]; !ok {
188 cache_allcounters[id] = m.registerCounter(opt)
189 }
190
191 c[opt.Name] = cache_allcounters[id]
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300192 }
193
194 return
195}
196
Juha Hyttinenf619d032020-05-07 12:42:26 +0300197/*
198 * Handling gauges
199 */
200func (m *Metrics) registerGauge(opts CounterOpts) Gauge {
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300201 Logger.Info("Register new gauge with opts: %v", opts)
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300202 return promauto.NewGauge(prometheus.GaugeOpts(opts))
203}
204
205func (m *Metrics) RegisterGaugeGroup(opts []CounterOpts, subsytem string) (c map[string]Gauge) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200206 globalLock.Lock()
207 defer globalLock.Unlock()
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300208 c = make(map[string]Gauge)
209 for _, opt := range opts {
210 opt.Namespace = m.Namespace
211 opt.Subsystem = subsytem
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200212
213 id := m.getFullName(prometheus.Opts(opt), []string{})
214 if _, ok := cache_allgauges[id]; !ok {
215 cache_allgauges[id] = m.registerGauge(opt)
216 }
217
218 c[opt.Name] = cache_allgauges[id]
Mohamed Abukar2e78e422019-06-02 11:45:52 +0300219 }
220
221 return
222}
Juha Hyttinenf619d032020-05-07 12:42:26 +0300223
224/*
225 * Handling counter vectors
226 *
227 * Example:
228
229 vec := Metric.RegisterCounterVecGroup(
230 []CounterOpts{
231 {Name: "counter1", Help: "counter1"},
232 {Name: "counter2", Help: "counter2"},
233 },
234 []string{"host"},
235 "SUBSYSTEM")
236
237 stat:=Metric.GetCounterGroupFromVects([]string{"localhost:8888"}, vec)
238
239*/
240type CounterVec struct {
241 Vec *prometheus.CounterVec
242 Opts CounterOpts
243}
244
245func (m *Metrics) registerCounterVec(opts CounterOpts, labelNames []string) *prometheus.CounterVec {
246 Logger.Info("Register new counter vector with opts: %v labelNames: %v", opts, labelNames)
Juha Hyttinenf619d032020-05-07 12:42:26 +0300247 return promauto.NewCounterVec(prometheus.CounterOpts(opts), labelNames)
248}
249
250func (m *Metrics) RegisterCounterVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]CounterVec) {
251 c = make(map[string]CounterVec)
252 for _, opt := range opts {
253 entry := CounterVec{}
254 entry.Opts = opt
255 entry.Opts.Namespace = m.Namespace
256 entry.Opts.Subsystem = subsytem
257 entry.Vec = m.registerCounterVec(entry.Opts, labelNames)
258 c[opt.Name] = entry
259 }
260 return
261}
262
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300263func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200264 globalLock.Lock()
265 defer globalLock.Unlock()
Juha Hyttinenf619d032020-05-07 12:42:26 +0300266 c = make(map[string]Counter)
267 for _, vec := range vects {
268 for name, opt := range vec {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200269
270 id := m.getFullName(prometheus.Opts(opt.Opts), labels)
271 if _, ok := cache_allcounters[id]; !ok {
272 Logger.Info("Register new counter from vector with opts: %v labels: %v prefix: %s", opt.Opts, labels, prefix)
273 cache_allcounters[id] = opt.Vec.WithLabelValues(labels...)
274 }
275 c[prefix+name] = cache_allcounters[id]
Juha Hyttinenf619d032020-05-07 12:42:26 +0300276 }
277 }
278 return
279}
280
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300281func (m *Metrics) GetCounterGroupFromVects(labels []string, vects ...map[string]CounterVec) (c map[string]Counter) {
282 return m.GetCounterGroupFromVectsWithPrefix("", labels, vects...)
283}
284
Juha Hyttinenf619d032020-05-07 12:42:26 +0300285/*
286 * Handling gauge vectors
287 *
288 * Example:
289
290 vec := Metric.RegisterGaugeVecGroup(
291 []CounterOpts{
292 {Name: "gauge1", Help: "gauge1"},
293 {Name: "gauge2", Help: "gauge2"},
294 },
295 []string{"host"},
296 "SUBSYSTEM")
297
298 stat:=Metric.GetGaugeGroupFromVects([]string{"localhost:8888"},vec)
299
300*/
301type GaugeVec struct {
302 Vec *prometheus.GaugeVec
303 Opts CounterOpts
304}
305
306func (m *Metrics) registerGaugeVec(opts CounterOpts, labelNames []string) *prometheus.GaugeVec {
307 Logger.Info("Register new gauge vector with opts: %v labelNames: %v", opts, labelNames)
Juha Hyttinenf619d032020-05-07 12:42:26 +0300308 return promauto.NewGaugeVec(prometheus.GaugeOpts(opts), labelNames)
309}
310
311func (m *Metrics) RegisterGaugeVecGroup(opts []CounterOpts, labelNames []string, subsytem string) (c map[string]GaugeVec) {
312 c = make(map[string]GaugeVec)
313 for _, opt := range opts {
314 entry := GaugeVec{}
315 entry.Opts = opt
316 entry.Opts.Namespace = m.Namespace
317 entry.Opts.Subsystem = subsytem
318 entry.Vec = m.registerGaugeVec(entry.Opts, labelNames)
319 c[opt.Name] = entry
320
321 }
322 return
323}
324
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300325func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200326 globalLock.Lock()
327 defer globalLock.Unlock()
Juha Hyttinenf619d032020-05-07 12:42:26 +0300328 c = make(map[string]Gauge)
329 for _, vec := range vects {
330 for name, opt := range vec {
Juha Hyttinen5bfa60a2020-10-30 10:31:39 +0200331
332 id := m.getFullName(prometheus.Opts(opt.Opts), labels)
333 if _, ok := cache_allgauges[id]; !ok {
334 Logger.Info("Register new gauge from vector with opts: %v labels: %v prefix: %s", opt.Opts, labels, prefix)
335 cache_allgauges[id] = opt.Vec.WithLabelValues(labels...)
336 }
337 c[prefix+name] = cache_allgauges[id]
Juha Hyttinenf619d032020-05-07 12:42:26 +0300338 }
339 }
340 return
341}
342
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300343func (m *Metrics) GetGaugeGroupFromVects(labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) {
344 return m.GetGaugeGroupFromVectsWithPrefix("", labels, vects...)
Juha Hyttinen90f6dd42020-05-08 12:17:05 +0300345}