Skip to content

Commit

Permalink
Add support for exemplars on constHistogram
Browse files Browse the repository at this point in the history
Co-authored-by: William Perron <william.perron@shopify.com>
Signed-off-by: William Perron <william.perron@shopify.com>
  • Loading branch information
arun-shopify and wperron committed Feb 10, 2022
1 parent 5ac1e92 commit 06d7406
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
59 changes: 58 additions & 1 deletion prometheus/examples_test.go
Expand Up @@ -16,6 +16,7 @@ package prometheus_test
import (
"bytes"
"fmt"
"google.golang.org/protobuf/types/known/timestamppb"
"math"
"net/http"
"runtime"
Expand Down Expand Up @@ -549,11 +550,27 @@ func ExampleNewConstHistogram() {
prometheus.Labels{"owner": "example"},
)

var exemplars []*dto.Exemplar
n := "testName"
v := "testVal"
lp := dto.LabelPair{Name: &n, Value: &v}
var labelPairs []*dto.LabelPair
labelPairs = append(labelPairs, &lp)
val := float64(42)
t, _ := time.Parse("unix", "Mon Jan _2 15:04:05 MST 2006")
ts := timestamppb.New(t)

for i := 0; i < 4; i++ {
e := dto.Exemplar{Label: labelPairs, Value: &val, Timestamp: ts}
exemplars = append(exemplars, &e)
}

// Create a constant histogram from values we got from a 3rd party telemetry system.
h := prometheus.MustNewConstHistogram(
h := prometheus.MustNewConstHistogramWithExemplar(
desc,
4711, 403.34,
map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233},
exemplars,
"200", "get",
)

Expand Down Expand Up @@ -583,18 +600,58 @@ func ExampleNewConstHistogram() {
// bucket: <
// cumulative_count: 121
// upper_bound: 25
// exemplar: <
// label: <
// name: "testName"
// value: "testVal"
// >
// value: 42
// timestamp: <
// seconds: -62135596800
// >
// >
// >
// bucket: <
// cumulative_count: 2403
// upper_bound: 50
// exemplar: <
// label: <
// name: "testName"
// value: "testVal"
// >
// value: 42
// timestamp: <
// seconds: -62135596800
// >
// >
// >
// bucket: <
// cumulative_count: 3221
// upper_bound: 100
// exemplar: <
// label: <
// name: "testName"
// value: "testVal"
// >
// value: 42
// timestamp: <
// seconds: -62135596800
// >
// >
// >
// bucket: <
// cumulative_count: 4233
// upper_bound: 200
// exemplar: <
// label: <
// name: "testName"
// value: "testVal"
// >
// value: 42
// timestamp: <
// seconds: -62135596800
// >
// >
// >
// >
}
Expand Down
59 changes: 58 additions & 1 deletion prometheus/histogram.go
Expand Up @@ -573,6 +573,7 @@ type constHistogram struct {
sum float64
buckets map[float64]uint64
labelPairs []*dto.LabelPair
exemplars []*dto.Exemplar
}

func (h *constHistogram) Desc() *Desc {
Expand All @@ -585,7 +586,6 @@ func (h *constHistogram) Write(out *dto.Metric) error {

his.SampleCount = proto.Uint64(h.count)
his.SampleSum = proto.Float64(h.sum)

for upperBound, count := range h.buckets {
buckets = append(buckets, &dto.Bucket{
CumulativeCount: proto.Uint64(count),
Expand All @@ -596,6 +596,13 @@ func (h *constHistogram) Write(out *dto.Metric) error {
if len(buckets) > 0 {
sort.Sort(buckSort(buckets))
}

if len(h.exemplars) > 0 {
for i := 0; i < len(buckets); i++ {
buckets[i].Exemplar = h.exemplars[i]
}
}

his.Bucket = buckets

out.Histogram = his
Expand All @@ -604,6 +611,13 @@ func (h *constHistogram) Write(out *dto.Metric) error {
return nil
}

func (h *constHistogram) GetExemplars() []*dto.Exemplar {
if h != nil {
return h.exemplars
}
return nil
}

// NewConstHistogram returns a metric representing a Prometheus histogram with
// fixed values for the count, sum, and bucket counts. As those parameters
// cannot be changed, the returned value does not implement the Histogram
Expand All @@ -617,6 +631,7 @@ func (h *constHistogram) Write(out *dto.Metric) error {
//
// NewConstHistogram returns an error if the length of labelValues is not
// consistent with the variable labels in Desc or if Desc is invalid.

func NewConstHistogram(
desc *Desc,
count uint64,
Expand Down Expand Up @@ -655,6 +670,48 @@ func MustNewConstHistogram(
return m
}

func NewConstHistogramWithExemplar(
desc *Desc,
count uint64,
sum float64,
buckets map[float64]uint64,
exemplars []*dto.Exemplar,
labelValues ...string,

) (Metric, error) {
if desc.err != nil {
return nil, desc.err
}
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
return nil, err
}
return &constHistogram{
desc: desc,
count: count,
sum: sum,
buckets: buckets,
exemplars: exemplars,
labelPairs: MakeLabelPairs(desc, labelValues),
}, nil
}

// MustNewConstHistogram is a version of NewConstHistogram that panics where
// NewConstHistogram would have returned an error.
func MustNewConstHistogramWithExemplar(
desc *Desc,
count uint64,
sum float64,
buckets map[float64]uint64,
exemplars []*dto.Exemplar,
labelValues ...string,
) Metric {
m, err := NewConstHistogramWithExemplar(desc, count, sum, buckets, exemplars, labelValues...)
if err != nil {
panic(err)
}
return m
}

type buckSort []*dto.Bucket

func (s buckSort) Len() int {
Expand Down

0 comments on commit 06d7406

Please sign in to comment.