add constant labels to gauges and cumulative metrics (#1122)
* Remove unused GetEntry.
* adds support for constant labels on Gauge and CumulativeMetric
* fixing format on tests.
* remove unused getentry
diff --git a/metric/common.go b/metric/common.go
index f5716c9..bd6e771 100644
--- a/metric/common.go
+++ b/metric/common.go
@@ -19,6 +19,7 @@
"time"
"go.opencensus.io/internal/tagencoding"
+
"go.opencensus.io/metric/metricdata"
)
@@ -30,11 +31,12 @@
// baseMetric should not be used directly, use metric specific type such as
// Float64Gauge or Int64Gauge.
type baseMetric struct {
- vals sync.Map
- desc metricdata.Descriptor
- start time.Time
- keys []metricdata.LabelKey
- bmType baseMetricType
+ vals sync.Map
+ desc metricdata.Descriptor
+ start time.Time
+ keys []metricdata.LabelKey
+ constLabelValues []metricdata.LabelValue
+ bmType baseMetricType
}
type baseMetricType int
@@ -118,6 +120,7 @@
}
func (bm *baseMetric) entryForValues(labelVals []metricdata.LabelValue, newEntry func() baseEntry) (interface{}, error) {
+ labelVals = append(bm.constLabelValues, labelVals...)
if len(labelVals) != len(bm.keys) {
return nil, errKeyValueMismatch
}
diff --git a/metric/cumulative_test.go b/metric/cumulative_test.go
index 6b2110d..98bda94 100644
--- a/metric/cumulative_test.go
+++ b/metric/cumulative_test.go
@@ -19,6 +19,7 @@
"time"
"github.com/google/go-cmp/cmp"
+
"go.opencensus.io/metric/metricdata"
)
@@ -83,6 +84,61 @@
}
}
+func TestCumulativeConstLabel(t *testing.T) {
+ r := NewRegistry()
+
+ f, _ := r.AddFloat64Cumulative("TestCumulativeWithConstLabel",
+ WithLabelKeys("k1"),
+ WithConstLabel(map[metricdata.LabelKey]metricdata.LabelValue{
+ {Key: "const"}: metricdata.NewLabelValue("same"),
+ {Key: "const2"}: metricdata.NewLabelValue("same2"),
+ }))
+
+ e, _ := f.GetEntry(metricdata.LabelValue{})
+ e.Inc(5)
+ e, _ = f.GetEntry(metricdata.NewLabelValue("k1v1"))
+ e.Inc(1)
+ m := r.Read()
+ want := []*metricdata.Metric{
+ {
+ Descriptor: metricdata.Descriptor{
+ Name: "TestCumulativeWithConstLabel",
+ LabelKeys: []metricdata.LabelKey{
+ {Key: "const"},
+ {Key: "const2"},
+ {Key: "k1"}},
+ Type: metricdata.TypeCumulativeFloat64,
+ },
+ TimeSeries: []*metricdata.TimeSeries{
+ {
+ LabelValues: []metricdata.LabelValue{
+ metricdata.NewLabelValue("same"),
+ metricdata.NewLabelValue("same2"),
+ {}},
+ Points: []metricdata.Point{
+ metricdata.NewFloat64Point(time.Time{}, 5),
+ },
+ },
+ {
+ LabelValues: []metricdata.LabelValue{
+ metricdata.NewLabelValue("same"),
+ metricdata.NewLabelValue("same2"),
+ metricdata.NewLabelValue("k1v1"),
+ },
+ Points: []metricdata.Point{
+ metricdata.NewFloat64Point(time.Time{}, 1),
+ },
+ },
+ },
+ },
+ }
+ canonicalize(m)
+ canonicalize(want)
+ if diff := cmp.Diff(m, want, cmp.Comparer(ignoreTimes)); diff != "" {
+ t.Errorf("-got +want: %s", diff)
+ }
+}
+
func TestCumulativeMetricDescriptor(t *testing.T) {
r := NewRegistry()
diff --git a/metric/gauge_test.go b/metric/gauge_test.go
index a352d2d..9c4f269 100644
--- a/metric/gauge_test.go
+++ b/metric/gauge_test.go
@@ -16,12 +16,13 @@
import (
"fmt"
- "go.opencensus.io/metric/metricdata"
"sort"
"testing"
"time"
"github.com/google/go-cmp/cmp"
+
+ "go.opencensus.io/metric/metricdata"
)
func TestGauge(t *testing.T) {
@@ -85,6 +86,62 @@
}
}
+func TestGaugeConstLabel(t *testing.T) {
+ r := NewRegistry()
+
+ f, _ := r.AddFloat64Gauge("TestGaugeWithConstLabel",
+ WithLabelKeys("k1"),
+ WithConstLabel(map[metricdata.LabelKey]metricdata.LabelValue{
+ {Key: "const"}: metricdata.NewLabelValue("same"),
+ {Key: "const2"}: metricdata.NewLabelValue("same2"),
+ }))
+
+ e, _ := f.GetEntry(metricdata.LabelValue{})
+ e.Set(5)
+ e, _ = f.GetEntry(metricdata.NewLabelValue("k1v1"))
+ e.Add(1)
+ m := r.Read()
+ want := []*metricdata.Metric{
+ {
+ Descriptor: metricdata.Descriptor{
+ Name: "TestGaugeWithConstLabel",
+ LabelKeys: []metricdata.LabelKey{
+ {Key: "const"},
+ {Key: "const2"},
+ {Key: "k1"}},
+ Type: metricdata.TypeGaugeFloat64,
+ },
+ TimeSeries: []*metricdata.TimeSeries{
+ {
+ LabelValues: []metricdata.LabelValue{
+ metricdata.NewLabelValue("same"),
+ metricdata.NewLabelValue("same2"),
+ {},
+ },
+ Points: []metricdata.Point{
+ metricdata.NewFloat64Point(time.Time{}, 5),
+ },
+ },
+ {
+ LabelValues: []metricdata.LabelValue{
+ metricdata.NewLabelValue("same"),
+ metricdata.NewLabelValue("same2"),
+ metricdata.NewLabelValue("k1v1"),
+ },
+ Points: []metricdata.Point{
+ metricdata.NewFloat64Point(time.Time{}, 1),
+ },
+ },
+ },
+ },
+ }
+ canonicalize(m)
+ canonicalize(want)
+ if diff := cmp.Diff(m, want, cmp.Comparer(ignoreTimes)); diff != "" {
+ t.Errorf("-got +want: %s", diff)
+ }
+}
+
func TestGaugeMetricDescriptor(t *testing.T) {
r := NewRegistry()
@@ -330,20 +387,18 @@
for _, m := range ms {
sort.Slice(m.TimeSeries, func(i, j int) bool {
// sort time series by their label values
- iLabels := m.TimeSeries[i].LabelValues
- jLabels := m.TimeSeries[j].LabelValues
- for k := 0; k < len(iLabels); k++ {
- if !iLabels[k].Present {
- if jLabels[k].Present {
- return true
- }
- } else if !jLabels[k].Present {
- return false
- } else {
- return iLabels[k].Value < jLabels[k].Value
- }
+ iStr := ""
+
+ for _, label := range m.TimeSeries[i].LabelValues {
+ iStr += fmt.Sprintf("%+v", label)
}
- panic("should have returned")
+
+ jStr := ""
+ for _, label := range m.TimeSeries[j].LabelValues {
+ jStr += fmt.Sprintf("%+v", label)
+ }
+
+ return iStr < jStr
})
}
}
diff --git a/metric/registry.go b/metric/registry.go
index ceea7e9..6c58ff9 100644
--- a/metric/registry.go
+++ b/metric/registry.go
@@ -15,6 +15,7 @@
package metric
import (
+ "sort"
"sync"
"time"
@@ -28,11 +29,11 @@
baseMetrics sync.Map
}
-//TODO: [rghetia] add constant labels.
type metricOptions struct {
- unit metricdata.Unit
- labelkeys []metricdata.LabelKey
- desc string
+ unit metricdata.Unit
+ labelkeys []metricdata.LabelKey
+ constLabels map[metricdata.LabelKey]metricdata.LabelValue
+ desc string
}
// Options apply changes to metricOptions.
@@ -70,6 +71,13 @@
}
}
+// WithConstLabel applies provided constant label.
+func WithConstLabel(constLabels map[metricdata.LabelKey]metricdata.LabelValue) Options {
+ return func(mo *metricOptions) {
+ mo.constLabels = constLabels
+ }
+}
+
// NewRegistry initializes a new Registry.
func NewRegistry() *Registry {
return &Registry{}
@@ -236,12 +244,28 @@
}
bm.start = time.Now()
o := createMetricOption(mos...)
- bm.keys = o.labelkeys
+
+ var constLabelKeys []metricdata.LabelKey
+ for k := range o.constLabels {
+ constLabelKeys = append(constLabelKeys, k)
+ }
+ sort.Slice(constLabelKeys, func(i, j int) bool {
+ return constLabelKeys[i].Key < constLabelKeys[j].Key
+ })
+
+ var constLabelValues []metricdata.LabelValue
+ for _, k := range constLabelKeys {
+ constLabelValues = append(constLabelValues, o.constLabels[k])
+ }
+
+ bm.keys = append(constLabelKeys, o.labelkeys...)
+ bm.constLabelValues = constLabelValues
+
bm.desc = metricdata.Descriptor{
Name: name,
Description: o.desc,
Unit: o.unit,
- LabelKeys: o.labelkeys,
+ LabelKeys: bm.keys,
Type: bmTypeToMetricType(bm),
}
r.baseMetrics.Store(name, bm)