Skip to content

Commit

Permalink
Extend Counters, Summaries and Histograms with creation timestamp
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Silva Sens <arthur.sens@coralogix.com>
  • Loading branch information
Arthur Silva Sens committed Aug 15, 2023
1 parent 51d24f8 commit 31ef8f7
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 17 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0
github.com/davecgh/go-spew v1.1.1
github.com/json-iterator/go v1.1.12
github.com/prometheus/client_model v0.4.0
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16
github.com/prometheus/common v0.44.0
github.com/prometheus/procfs v0.11.1
golang.org/x/sys v0.11.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
Expand Down
15 changes: 13 additions & 2 deletions prometheus/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

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

// Counter is a Metric that represents a single numerical value that only ever
Expand Down Expand Up @@ -90,8 +91,12 @@ func NewCounter(opts CounterOpts) Counter {
nil,
opts.ConstLabels,
)
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now}
if opts.now == nil {
opts.now = time.Now
}
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: opts.now}
result.init(result) // Init self-collection.
result.createdTs = timestamppb.New(opts.now())
return result
}

Expand All @@ -106,6 +111,7 @@ type counter struct {
selfCollector
desc *Desc

createdTs *timestamppb.Timestamp
labelPairs []*dto.LabelPair
exemplar atomic.Value // Containing nil or a *dto.Exemplar.

Expand Down Expand Up @@ -160,7 +166,8 @@ func (c *counter) Write(out *dto.Metric) error {
}
val := c.get()

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

func (c *counter) updateExemplar(v float64, l Labels) {
Expand Down Expand Up @@ -200,13 +207,17 @@ func (v2) NewCounterVec(opts CounterVecOpts) *CounterVec {
opts.VariableLabels,
opts.ConstLabels,
)
if opts.now == nil {
opts.now = time.Now
}
return &CounterVec{
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
if len(lvs) != len(desc.variableLabels.names) {
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, lvs))
}
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
result.init(result) // Init self-collection.
result.createdTs = timestamppb.New(opts.now())
return result
}),
}
Expand Down
37 changes: 37 additions & 0 deletions prometheus/counter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,40 @@ func TestCounterExemplar(t *testing.T) {
t.Error("adding exemplar with oversized labels succeeded")
}
}

func TestCounterCreatedTimestamp(t *testing.T) {
now := time.Now()
counter := NewCounter(CounterOpts{
Name: "test",
Help: "test help",
now: func() time.Time { return now },
})

var metric dto.Metric
if err := counter.Write(&metric); err != nil {
t.Fatal(err)
}

if metric.Counter.CreatedTimestamp.AsTime().Unix() != now.Unix() {
t.Errorf("expected created timestamp %d, got %d", now.Unix(), metric.Counter.CreatedTimestamp.AsTime().Unix())
}
}

func TestCounterVecCreatedTimestamp(t *testing.T) {
now := time.Now()
counterVec := NewCounterVec(CounterOpts{
Name: "test",
Help: "test help",
now: func() time.Time { return now },
}, []string{"label"})
counter := counterVec.WithLabelValues("value")

var metric dto.Metric
if err := counter.Write(&metric); err != nil {
t.Fatal(err)
}

if metric.Counter.CreatedTimestamp.AsTime().Unix() != now.Unix() {
t.Errorf("expected created timestamp %d, got %d", now.Unix(), metric.Counter.CreatedTimestamp.AsTime().Unix())
}
}
2 changes: 1 addition & 1 deletion prometheus/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (g *gauge) Sub(val float64) {

func (g *gauge) Write(out *dto.Metric) error {
val := math.Float64frombits(atomic.LoadUint64(&g.valBits))
return populateMetric(GaugeValue, val, g.labelPairs, nil, out)
return populateMetric(GaugeValue, val, g.labelPairs, nil, out, nil)
}

// GaugeVec is a Collector that bundles a set of Gauges that all share the same
Expand Down
20 changes: 16 additions & 4 deletions prometheus/histogram.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
dto "github.com/prometheus/client_model/go"

"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)

// nativeHistogramBounds for the frac of observed values. Only relevant for
Expand Down Expand Up @@ -471,6 +472,8 @@ type HistogramOpts struct {
NativeHistogramMaxBucketNumber uint32
NativeHistogramMinResetDuration time.Duration
NativeHistogramMaxZeroThreshold float64

now func() time.Time // To mock out time.Now() for testing.
}

// HistogramVecOpts bundles the options to create a HistogramVec metric.
Expand Down Expand Up @@ -568,7 +571,11 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
atomic.StoreInt32(&h.counts[1].nativeHistogramSchema, h.nativeHistogramSchema)
h.exemplars = make([]atomic.Value, len(h.upperBounds)+1)

if opts.now == nil {
opts.now = time.Now
}
h.init(h) // Init self-collection.
h.createdTs = timestamppb.New(opts.now())
return h
}

Expand Down Expand Up @@ -707,6 +714,7 @@ type histogram struct {
nativeHistogramMaxBuckets uint32
nativeHistogramMinResetDuration time.Duration
lastResetTime time.Time // Protected by mtx.
createdTs *timestamppb.Timestamp

now func() time.Time // To mock out time.Now() for testing.
}
Expand Down Expand Up @@ -747,9 +755,10 @@ func (h *histogram) Write(out *dto.Metric) error {
waitForCooldown(count, coldCounts)

his := &dto.Histogram{
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
SampleCount: proto.Uint64(count),
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
SampleCount: proto.Uint64(count),
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
CreatedTimestamp: h.createdTs,
}
out.Histogram = his
out.Label = h.labelPairs
Expand Down Expand Up @@ -1194,14 +1203,17 @@ type constHistogram struct {
sum float64
buckets map[float64]uint64
labelPairs []*dto.LabelPair
createdTs *timestamppb.Timestamp
}

func (h *constHistogram) Desc() *Desc {
return h.desc
}

func (h *constHistogram) Write(out *dto.Metric) error {
his := &dto.Histogram{}
his := &dto.Histogram{
CreatedTimestamp: h.createdTs,
}

buckets := make([]*dto.Bucket, 0, len(h.buckets))

Expand Down
41 changes: 41 additions & 0 deletions prometheus/histogram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1152,3 +1152,44 @@ func TestGetLe(t *testing.T) {
}
}
}

func TestHistogramCreatedTimestamp(t *testing.T) {
now := time.Now()

histogram := NewHistogram(HistogramOpts{
Name: "test",
Help: "test help",
Buckets: []float64{1, 2, 3, 4},
now: func() time.Time { return now },
})

var metric dto.Metric
if err := histogram.Write(&metric); err != nil {
t.Fatal(err)
}

if metric.Histogram.CreatedTimestamp.AsTime().Unix() != now.Unix() {
t.Errorf("expected created timestamp %d, got %d", now.Unix(), metric.Histogram.CreatedTimestamp.AsTime().Unix())
}
}

func TestHistogramVecCreatedTimestamp(t *testing.T) {
now := time.Now()

histogramVec := NewHistogramVec(HistogramOpts{
Name: "test",
Help: "test help",
Buckets: []float64{1, 2, 3, 4},
now: func() time.Time { return now },
}, []string{"label"})
histogram := histogramVec.WithLabelValues("value").(Histogram)

var metric dto.Metric
if err := histogram.Write(&metric); err != nil {
t.Fatal(err)
}

if metric.Histogram.CreatedTimestamp.AsTime().Unix() != now.Unix() {
t.Errorf("expected created timestamp %d, got %d", now.Unix(), metric.Histogram.CreatedTimestamp.AsTime().Unix())
}
}
2 changes: 2 additions & 0 deletions prometheus/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ type Opts struct {
// machine_role metric). See also
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
ConstLabels Labels

now func() time.Time // To mock out time.Now() for testing.
}

// BuildFQName joins the given three name components by "_". Empty name
Expand Down
26 changes: 22 additions & 4 deletions prometheus/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/beorn7/perks/quantile"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)

// quantileLabel is used for the label that defines the quantile in a
Expand Down Expand Up @@ -145,6 +146,8 @@ type SummaryOpts struct {
// is the internal buffer size of the underlying package
// "github.com/bmizerany/perks/quantile").
BufCap uint32

now func() time.Time // To mock out time.Now() for testing.
}

// SummaryVecOpts bundles the options to create a SummaryVec metric.
Expand Down Expand Up @@ -222,6 +225,9 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
opts.BufCap = DefBufCap
}

if opts.now == nil {
opts.now = time.Now
}
if len(opts.Objectives) == 0 {
// Use the lock-free implementation of a Summary without objectives.
s := &noObjectivesSummary{
Expand All @@ -230,6 +236,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
counts: [2]*summaryCounts{{}, {}},
}
s.init(s) // Init self-collection.
s.createdTs = timestamppb.New(opts.now())
return s
}

Expand Down Expand Up @@ -259,6 +266,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
sort.Float64s(s.sortedObjectives)

s.init(s) // Init self-collection.
s.createdTs = timestamppb.New(opts.now())
return s
}

Expand Down Expand Up @@ -286,6 +294,8 @@ type summary struct {
headStream *quantile.Stream
headStreamIdx int
headStreamExpTime, hotBufExpTime time.Time

createdTs *timestamppb.Timestamp
}

func (s *summary) Desc() *Desc {
Expand All @@ -307,7 +317,9 @@ func (s *summary) Observe(v float64) {
}

func (s *summary) Write(out *dto.Metric) error {
sum := &dto.Summary{}
sum := &dto.Summary{
CreatedTimestamp: s.createdTs,
}
qs := make([]*dto.Quantile, 0, len(s.objectives))

s.bufMtx.Lock()
Expand Down Expand Up @@ -440,6 +452,8 @@ type noObjectivesSummary struct {
counts [2]*summaryCounts

labelPairs []*dto.LabelPair

createdTs *timestamppb.Timestamp
}

func (s *noObjectivesSummary) Desc() *Desc {
Expand Down Expand Up @@ -490,8 +504,9 @@ func (s *noObjectivesSummary) Write(out *dto.Metric) error {
}

sum := &dto.Summary{
SampleCount: proto.Uint64(count),
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
SampleCount: proto.Uint64(count),
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
CreatedTimestamp: s.createdTs,
}

out.Summary = sum
Expand Down Expand Up @@ -681,14 +696,17 @@ type constSummary struct {
sum float64
quantiles map[float64]float64
labelPairs []*dto.LabelPair
createdTs *timestamppb.Timestamp
}

func (s *constSummary) Desc() *Desc {
return s.desc
}

func (s *constSummary) Write(out *dto.Metric) error {
sum := &dto.Summary{}
sum := &dto.Summary{
CreatedTimestamp: s.createdTs,
}
qs := make([]*dto.Quantile, 0, len(s.quantiles))

sum.SampleCount = proto.Uint64(s.count)
Expand Down
Loading

0 comments on commit 31ef8f7

Please sign in to comment.