Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

Commit

Permalink
add constant labels to gauges and cumulative metrics (#1122)
Browse files Browse the repository at this point in the history
* Remove unused GetEntry.

* adds support for constant labels on Gauge and CumulativeMetric

* fixing format on tests.

* remove unused getentry
  • Loading branch information
paivagustavo authored and rghetia committed Apr 25, 2019
1 parent 3e65bcb commit c31d268
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 25 deletions.
13 changes: 8 additions & 5 deletions metric/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"time"

"go.opencensus.io/internal/tagencoding"

"go.opencensus.io/metric/metricdata"
)

Expand All @@ -30,11 +31,12 @@ import (
// 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
Expand Down Expand Up @@ -118,6 +120,7 @@ func (bm *baseMetric) decodeLabelVals(s string) []metricdata.LabelValue {
}

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
}
Expand Down
56 changes: 56 additions & 0 deletions metric/cumulative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"time"

"github.com/google/go-cmp/cmp"

"go.opencensus.io/metric/metricdata"
)

Expand Down Expand Up @@ -83,6 +84,61 @@ func TestCumulative(t *testing.T) {
}
}

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()

Expand Down
83 changes: 69 additions & 14 deletions metric/gauge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ package metric

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) {
Expand Down Expand Up @@ -85,6 +86,62 @@ func TestGauge(t *testing.T) {
}
}

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()

Expand Down Expand Up @@ -330,20 +387,18 @@ func canonicalize(ms []*metricdata.Metric) {
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
})
}
}
Expand Down
36 changes: 30 additions & 6 deletions metric/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package metric

import (
"sort"
"sync"
"time"

Expand All @@ -28,11 +29,11 @@ type Registry struct {
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.
Expand Down Expand Up @@ -70,6 +71,13 @@ func WithLabelKeysAndDescription(labelKeys ...metricdata.LabelKey) Options {
}
}

// 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{}
Expand Down Expand Up @@ -236,12 +244,28 @@ func (r *Registry) initBaseMetric(bm *baseMetric, name string, mos ...Options) (
}
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)
Expand Down

0 comments on commit c31d268

Please sign in to comment.