From 90f6dd45c9874dbfa8673fc1c0e12a3595951241 Mon Sep 17 00:00:00 2001 From: Juha Hyttinen Date: Fri, 8 May 2020 12:17:05 +0300 Subject: [PATCH] ========= Added support for name prefix when creating group from vector Example: vect:=RegisterCounterVecGroup( []CounterOpts{{Name: "counter", Help: "counter"},}, []string{"name", "event"}, "SUBSSYSTEM") grp1:=GetCounterGroupFromVectsWithPrefix("event1_", []string{"name1", "event1"}, vect) grp2:=GetCounterGroupFromVectsWithPrefix("event2_", []string{"name1", "event2"}, vect) grp:=CombineCounterGroups(grp1,grp2) grp["event1_counter"].Inc() -> increments "counter" (NAMESPACE_SUBSYSTEM_counter) with labels: "name=name1", "event=event1" grp["event2_counter"].Inc() -> increments "counter" (NAMESPACE_SUBSYSTEM_counter) with labels: "name=name1", "event=event2" ========= Added cache support for created metric groups Example (uses prev example groups): cacheid := "CACHEID" entry := xapp.Metric.GroupCacheGet(cacheid) if entry == nil { xapp.Metric.GroupCacheAddCounters(cacheid, grp1) xapp.Metric.GroupCacheAddCounters(cacheid, grp2) entry = xapp.Metric.GroupCacheGet(cacheid) } entry.Counters["event1_counter"].Inc() -> increments "counter" (NAMESPACE_SUBSYSTEM_counter) with labels: "name=name1", "event=event1" entry.Counters["event2_counter"].Inc() -> increments "counter" (NAMESPACE_SUBSYSTEM_counter) with labels: "name=name1", "event=event2" Change-Id: Ic9b827d1dbf32a344302d7974457edf9411d2b78 Signed-off-by: Juha Hyttinen --- pkg/xapp/metrics.go | 71 +++++++++++++-- pkg/xapp/metrics_test.go | 222 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 pkg/xapp/metrics_test.go diff --git a/pkg/xapp/metrics.go b/pkg/xapp/metrics.go index d2d801c..aa4b0f7 100644 --- a/pkg/xapp/metrics.go +++ b/pkg/xapp/metrics.go @@ -26,15 +26,30 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -type Metrics struct { - Namespace string -} - +//----------------------------------------------------------------------------- // Alias +//----------------------------------------------------------------------------- type CounterOpts prometheus.Opts type Counter prometheus.Counter type Gauge prometheus.Gauge +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +type MetricGroupsCache struct { + Counters map[string]Counter + Gauges map[string]Gauge +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +type Metrics struct { + Namespace string + MetricGroupsCacheMap map[string]*MetricGroupsCache +} + func NewMetrics(url, namespace string, r *mux.Router) *Metrics { if url == "" { url = "/ric/v1/metrics" @@ -48,7 +63,7 @@ func NewMetrics(url, namespace string, r *mux.Router) *Metrics { // Expose 'metrics' endpoint with standard golang metrics used by prometheus r.Handle(url, promhttp.Handler()) - return &Metrics{Namespace: namespace} + return &Metrics{Namespace: namespace, MetricGroupsCacheMap: make(map[string]*MetricGroupsCache)} } /* @@ -129,17 +144,21 @@ func (m *Metrics) RegisterCounterVecGroup(opts []CounterOpts, labelNames []strin return } -func (m *Metrics) GetCounterGroupFromVects(labels []string, vects ...map[string]CounterVec) (c map[string]Counter) { +func (m *Metrics) GetCounterGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]CounterVec) (c map[string]Counter) { c = make(map[string]Counter) for _, vec := range vects { for name, opt := range vec { - c[name] = opt.Vec.WithLabelValues(labels...) + c[prefix+name] = opt.Vec.WithLabelValues(labels...) Logger.Info("Register new counter for vector with opts: %v labels: %v", opt.Opts, labels) } } return } +func (m *Metrics) GetCounterGroupFromVects(labels []string, vects ...map[string]CounterVec) (c map[string]Counter) { + return m.GetCounterGroupFromVectsWithPrefix("", labels, vects...) +} + /* * Handling gauge vectors * @@ -181,17 +200,22 @@ func (m *Metrics) RegisterGaugeVecGroup(opts []CounterOpts, labelNames []string, return } -func (m *Metrics) GetGaugeGroupFromVects(labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) { +func (m *Metrics) GetGaugeGroupFromVectsWithPrefix(prefix string, labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) { c = make(map[string]Gauge) for _, vec := range vects { for name, opt := range vec { - c[name] = opt.Vec.WithLabelValues(labels...) + c[prefix+name] = opt.Vec.WithLabelValues(labels...) Logger.Info("Register new gauge for vector with opts: %v labels: %v", opt.Opts, labels) } } return } +func (m *Metrics) GetGaugeGroupFromVects(labels []string, vects ...map[string]GaugeVec) (c map[string]Gauge) { + return m.GetGaugeGroupFromVectsWithPrefix("", labels, vects...) + +} + /* * */ @@ -214,3 +238,32 @@ func (m *Metrics) CombineGaugeGroups(srcs ...map[string]Gauge) map[string]Gauge } return trg } + +/* + * + */ +func (m *Metrics) GroupCacheGet(id string) *MetricGroupsCache { + entry, ok := m.MetricGroupsCacheMap[id] + if ok == false { + return nil + } + return entry +} + +func (m *Metrics) GroupCacheAddCounters(id string, vals map[string]Counter) { + entry, ok := m.MetricGroupsCacheMap[id] + if ok == false { + entry = &MetricGroupsCache{} + m.MetricGroupsCacheMap[id] = entry + } + m.MetricGroupsCacheMap[id].Counters = m.CombineCounterGroups(m.MetricGroupsCacheMap[id].Counters, vals) +} + +func (m *Metrics) GroupCacheAddGauges(id string, vals map[string]Gauge) { + entry, ok := m.MetricGroupsCacheMap[id] + if ok == false { + entry = &MetricGroupsCache{} + m.MetricGroupsCacheMap[id] = entry + } + m.MetricGroupsCacheMap[id].Gauges = m.CombineGaugeGroups(m.MetricGroupsCacheMap[id].Gauges, vals) +} diff --git a/pkg/xapp/metrics_test.go b/pkg/xapp/metrics_test.go new file mode 100644 index 0000000..ff70ab3 --- /dev/null +++ b/pkg/xapp/metrics_test.go @@ -0,0 +1,222 @@ +/* +================================================================================== + Copyright (c) 2019 AT&T Intellectual Property. + Copyright (c) 2019 Nokia + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +================================================================================== +*/ + +package xapp + +import ( + "testing" +) + +var mCVect map[string]CounterVec +var mGVect map[string]GaugeVec + +func TestMetricSetup(t *testing.T) { + mCVect = Metric.RegisterCounterVecGroup( + []CounterOpts{ + {Name: "counter1", Help: "counter1"}, + }, + []string{"name", "event"}, + "SUBSYSTEM") + + mGVect = Metric.RegisterGaugeVecGroup( + []CounterOpts{ + {Name: "counter2", Help: "counter2"}, + }, + []string{"name", "event"}, + "SUBSYSTEM") +} + +func TestMetricCounterVector(t *testing.T) { + // + // + c_grp1 := Metric.GetCounterGroupFromVects([]string{"name1", "event1"}, mCVect) + if _, ok := c_grp1["counter1"]; ok == false { + t.Errorf("c_grp1 counter1 not exists") + } + c_grp1["counter1"].Inc() + + // + // + c_grp2 := Metric.GetCounterGroupFromVects([]string{"name1", "event2"}, mCVect) + if _, ok := c_grp2["counter1"]; ok == false { + t.Errorf("c_grp2 counter1 not exists") + } + c_grp2["counter1"].Inc() +} + +func TestMetricGaugeVector(t *testing.T) { + // + // + g_grp1 := Metric.GetGaugeGroupFromVects([]string{"name1", "event1"}, mGVect) + if _, ok := g_grp1["counter2"]; ok == false { + t.Errorf("g_grp1 counter2 not exists") + } + g_grp1["counter2"].Inc() + + // + // + g_grp2 := Metric.GetGaugeGroupFromVects([]string{"name1", "event2"}, mGVect) + if _, ok := g_grp2["counter2"]; ok == false { + t.Errorf("g_grp2 counter2 not exists") + } + g_grp2["counter2"].Inc() +} + +func TestMetricCounterVectorPrefix(t *testing.T) { + // + // + c_grp1 := Metric.GetCounterGroupFromVectsWithPrefix("event1_", []string{"name1", "event1"}, mCVect) + if _, ok := c_grp1["event1_counter1"]; ok == false { + t.Errorf("c_grp1 event1_counter1 not exists") + } + c_grp1["event1_counter1"].Inc() + + // + // + c_grp2 := Metric.GetCounterGroupFromVectsWithPrefix("event2_", []string{"name1", "event2"}, mCVect) + if _, ok := c_grp2["event2_counter1"]; ok == false { + t.Errorf("c_grp2 event2_counter1 not exists") + } + c_grp2["event2_counter1"].Inc() + + // + // + c_grp := Metric.CombineCounterGroups(c_grp1, c_grp2) + + // + // + if _, ok := c_grp["event1_counter1"]; ok == false { + t.Errorf("c_grp event1_counter1 not exists") + } + c_grp["event1_counter1"].Inc() + + // + // + if _, ok := c_grp["event2_counter1"]; ok == false { + t.Errorf("c_grp event2_counter1 not exists") + } + c_grp["event2_counter1"].Inc() +} + +func TestMetricGaugeVectorPrefix(t *testing.T) { + // + // + g_grp1 := Metric.GetGaugeGroupFromVectsWithPrefix("event1_", []string{"name1", "event1"}, mGVect) + if _, ok := g_grp1["event1_counter2"]; ok == false { + t.Errorf("g_grp1 event1_counter2 not exists") + } + g_grp1["event1_counter2"].Inc() + + // + // + g_grp2 := Metric.GetGaugeGroupFromVectsWithPrefix("event2_", []string{"name1", "event2"}, mGVect) + if _, ok := g_grp2["event2_counter2"]; ok == false { + t.Errorf("g_grp2 event2_counter2 not exists") + } + g_grp2["event2_counter2"].Inc() + + // + // + g_grp := Metric.CombineGaugeGroups(g_grp1, g_grp2) + + // + // + if _, ok := g_grp["event1_counter2"]; ok == false { + t.Errorf("g_grp event1_counter2 not exists") + } + g_grp["event1_counter2"].Inc() + + // + // + if _, ok := g_grp["event2_counter2"]; ok == false { + t.Errorf("g_grp event2_counter2 not exists") + } + g_grp["event2_counter2"].Inc() +} + +func TestMetricGroupCache(t *testing.T) { + // + // + c_grp1 := Metric.GetCounterGroupFromVectsWithPrefix("event1_", []string{"name1", "event1"}, mCVect) + if _, ok := c_grp1["event1_counter1"]; ok == false { + t.Errorf("c_grp1 event1_counter1 not exists") + } + c_grp1["event1_counter1"].Inc() + + // + // + c_grp2 := Metric.GetCounterGroupFromVectsWithPrefix("event2_", []string{"name1", "event2"}, mCVect) + if _, ok := c_grp2["event2_counter1"]; ok == false { + t.Errorf("c_grp2 event2_counter1 not exists") + } + c_grp2["event2_counter1"].Inc() + + // + // + g_grp1 := Metric.GetGaugeGroupFromVectsWithPrefix("event1_", []string{"name1", "event1"}, mGVect) + if _, ok := g_grp1["event1_counter2"]; ok == false { + t.Errorf("g_grp1 event1_counter2 not exists") + } + g_grp1["event1_counter2"].Inc() + + // + // + g_grp2 := Metric.GetGaugeGroupFromVectsWithPrefix("event2_", []string{"name1", "event2"}, mGVect) + if _, ok := g_grp2["event2_counter2"]; ok == false { + t.Errorf("g_grp2 event2_counter2 not exists") + } + g_grp2["event2_counter2"].Inc() + + // + // + cacheid := "CACHEID" + entry := Metric.GroupCacheGet(cacheid) + if entry == nil { + Metric.GroupCacheAddCounters(cacheid, c_grp1) + Metric.GroupCacheAddCounters(cacheid, c_grp2) + Metric.GroupCacheAddGauges(cacheid, g_grp1) + Metric.GroupCacheAddGauges(cacheid, g_grp2) + entry = Metric.GroupCacheGet(cacheid) + } + + if entry == nil { + t.Errorf("Cache failed") + } + + if _, ok := entry.Counters["event1_counter1"]; ok == false { + t.Errorf("entry.Counters event1_counter1 not exists") + } + entry.Counters["event1_counter1"].Inc() + + if _, ok := entry.Counters["event2_counter1"]; ok == false { + t.Errorf("entry.Counters event2_counter1 not exists") + } + entry.Counters["event2_counter1"].Inc() + + if _, ok := entry.Gauges["event1_counter2"]; ok == false { + t.Errorf("entry.Gauges event1_counter2 not exists") + } + entry.Gauges["event1_counter2"].Inc() + + if _, ok := entry.Gauges["event2_counter2"]; ok == false { + t.Errorf("entry.Gauges event2_counter2 not exists") + } + entry.Gauges["event2_counter2"].Inc() + +} -- 2.16.6