Skip to content

Commit

Permalink
Implement new function NewConstMetricWithCreatedTimestamp
Browse files Browse the repository at this point in the history
NewConstMetricWithCreatedTimestamp generates constant counters with created timestamp set. It returns errors if it receives other metric types.

Signed-off-by: Arthur Silva Sens <arthur.sens@coralogix.com>
  • Loading branch information
ArthurSens committed Jul 28, 2023
1 parent 4816192 commit fd84017
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 5 deletions.
4 changes: 2 additions & 2 deletions prometheus/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ func (c *counter) Write(out *dto.Metric) error {
exemplar = e.(*dto.Exemplar)
}
val := c.get()

return populateMetric(CounterValue, val, c.labelPairs, exemplar, out, c.createdTs)
ct := c.createdTs.AsTime()
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out, &ct)
}

func (c *counter) updateExemplar(v float64, l Labels) {
Expand Down
49 changes: 46 additions & 3 deletions prometheus/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package prometheus

import (
"errors"
"fmt"
"sort"
"time"
Expand Down Expand Up @@ -110,7 +111,7 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
}

metric := &dto.Metric{}
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, timestamppb.Now()); err != nil {
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, nil); err != nil {
return nil, err
}

Expand All @@ -130,6 +131,43 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
return m
}

// NewConstMetricWithCreatedTimestamp does the same thing as NewConstMetric, but generates Counters
// with created timestamp set and returns an error for other metric types.
func NewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) (Metric, error) {
if desc.err != nil {
return nil, desc.err
}
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
return nil, err
}
switch valueType {
case CounterValue:
break
default:
return nil, errors.New("Created timestamps are only supported for counters")
}

metric := &dto.Metric{}
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, &ct); err != nil {
return nil, err
}

return &constMetric{
desc: desc,
metric: metric,
}, nil
}

// MustNewConstMetricWithCreatedTimestamp is a version of NewConstMetricWithCreatedTimestamp that panics where
// NewConstMetricWithCreatedTimestamp would have returned an error.
func MustNewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) Metric {
m, err := NewConstMetricWithCreatedTimestamp(desc, valueType, value, ct, labelValues...)
if err != nil {
panic(err)
}
return m
}

type constMetric struct {
desc *Desc
metric *dto.Metric
Expand All @@ -153,12 +191,17 @@ func populateMetric(
labelPairs []*dto.LabelPair,
e *dto.Exemplar,
m *dto.Metric,
cTs *timestamppb.Timestamp,
createdTimestamp *time.Time,
) error {
var ct *timestamppb.Timestamp
if createdTimestamp != nil {
ct = timestamppb.New(*createdTimestamp)
}

m.Label = labelPairs
switch t {
case CounterValue:
m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e, CreatedTimestamp: cTs}
m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e, CreatedTimestamp: ct}
case GaugeValue:
m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
case UntypedValue:
Expand Down
56 changes: 56 additions & 0 deletions prometheus/value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ package prometheus
import (
"fmt"
"testing"
"time"

dto "github.com/prometheus/client_model/go"
"google.golang.org/protobuf/types/known/timestamppb"
)

func TestNewConstMetricInvalidLabelValues(t *testing.T) {
Expand Down Expand Up @@ -54,3 +58,55 @@ func TestNewConstMetricInvalidLabelValues(t *testing.T) {
}
}
}

func TestNewConstMetricWithCreatedTimestamp(t *testing.T) {
ct := time.Now()
testCases := []struct {
desc string
metricType ValueType
createdTimestamp time.Time
expecErr bool
expectedCt *timestamppb.Timestamp
}{
{
desc: "gauge with CT",
metricType: GaugeValue,
createdTimestamp: ct,
expecErr: true,
expectedCt: nil,
},
{
desc: "counter with CT",
metricType: CounterValue,
createdTimestamp: ct,
expecErr: false,
expectedCt: timestamppb.New(ct),
},
}

for _, test := range testCases {
metricDesc := NewDesc(
"sample_value",
"sample value",
nil,
nil,
)
m, err := NewConstMetricWithCreatedTimestamp(metricDesc, test.metricType, float64(1), test.createdTimestamp)

if test.expecErr && err == nil {
t.Errorf("Expected error is test %s, got no err", test.desc)
}

if !test.expecErr && err != nil {
t.Errorf("Didn't expect error in test %s, got %s", test.desc, err.Error())
}

if test.expectedCt != nil {
var metric dto.Metric
m.Write(&metric)
if metric.Counter.CreatedTimestamp.AsTime() != test.expectedCt.AsTime() {
t.Errorf("Expected timestamp %v, got %v", test.expectedCt, &metric.Counter.CreatedTimestamp)
}
}
}
}

0 comments on commit fd84017

Please sign in to comment.