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

Commit

Permalink
Add labeled Prometheus summary (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlipa91 committed Dec 30, 2021
1 parent 7a05197 commit df5879c
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 11 deletions.
6 changes: 3 additions & 3 deletions promutils/labeled/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
)

// Represents a counter labeled with values from the context. See labeled.SetMetricsKeys for information about to
// Represents a counter labeled with values from the context. See labeled.SetMetricsKeys for information about how to
// configure that.
type Counter struct {
*prometheus.CounterVec
Expand All @@ -18,7 +18,7 @@ type Counter struct {
}

// Inc increments the counter by 1. Use Add to increment it by arbitrary non-negative values. The data point will be
// labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (c Counter) Inc(ctx context.Context) {
counter, err := c.CounterVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, c.additionalLabels...)...))
if err != nil {
Expand All @@ -32,7 +32,7 @@ func (c Counter) Inc(ctx context.Context) {
}

// Add adds the given value to the counter. It panics if the value is < 0.. The data point will be labeled with values
// from context. See labeled.SetMetricsKeys for information about to configure that.
// from context. See labeled.SetMetricsKeys for information about how to configure that.
func (c Counter) Add(ctx context.Context, v float64) {
counter, err := c.CounterVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, c.additionalLabels...)...))
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions promutils/labeled/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Gauge struct {
}

// Inc increments the gauge by 1. Use Add to increment by arbitrary values. The data point will be
// labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (g Gauge) Inc(ctx context.Context) {
gauge, err := g.GaugeVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, g.additionalLabels...)...))
if err != nil {
Expand All @@ -31,7 +31,7 @@ func (g Gauge) Inc(ctx context.Context) {
}

// Add adds the given value to the Gauge. (The value can be negative, resulting in a decrease of the Gauge.)
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (g Gauge) Add(ctx context.Context, v float64) {
gauge, err := g.GaugeVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, g.additionalLabels...)...))
if err != nil {
Expand All @@ -45,7 +45,7 @@ func (g Gauge) Add(ctx context.Context, v float64) {
}

// Set sets the Gauge to an arbitrary value.
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (g Gauge) Set(ctx context.Context, v float64) {
gauge, err := g.GaugeVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, g.additionalLabels...)...))
if err != nil {
Expand All @@ -59,7 +59,7 @@ func (g Gauge) Set(ctx context.Context, v float64) {
}

// Dec decrements the level by 1. Use Sub to decrement by arbitrary values. The data point will be
// labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (g Gauge) Dec(ctx context.Context) {
gauge, err := g.GaugeVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, g.additionalLabels...)...))
if err != nil {
Expand All @@ -73,7 +73,7 @@ func (g Gauge) Dec(ctx context.Context) {
}

// Sub adds the given value to the Gauge. The value can be negative, resulting in an increase of the Gauge.
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about to configure that.
// The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about how to configure that.
func (g Gauge) Sub(ctx context.Context, v float64) {
gauge, err := g.GaugeVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, g.additionalLabels...)...))
if err != nil {
Expand Down Expand Up @@ -101,7 +101,7 @@ func (g Gauge) SetToCurrentTime(ctx context.Context) {

// Creates a new labeled gauge. Label keys must be set before instantiating. If the unlabeled option is given,
// this object will also instantiate and emit another gauge with the given name with an _unlabeled suffix.
// See labeled.SetMetricsKeys for information about to configure that.
// See labeled.SetMetricsKeys for information about how to configure that.
func NewGauge(name, description string, scope promutils.Scope, opts ...MetricOption) Gauge {
if len(metricKeys) == 0 {
panic(ErrNeverSet)
Expand Down
4 changes: 2 additions & 2 deletions promutils/labeled/stopwatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (c StopWatch) Start(ctx context.Context) Timer {
}

// Observes specified duration between the start and end time. The data point will be labeled with values from context.
// See labeled.SetMetricsKeys for information about to configure that.
// See labeled.SetMetricsKeys for information about how to configure that.
func (c StopWatch) Observe(ctx context.Context, start, end time.Time) {
w, err := c.StopWatchVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, c.additionalLabels...)...))
if err != nil {
Expand All @@ -69,7 +69,7 @@ func (c StopWatch) Time(ctx context.Context, f func()) {
}

// Creates a new labeled stopwatch. Label keys must be set before instantiating a counter. See labeled.SetMetricsKeys
// for information about to configure that.
// for information about how to configure that.
func NewStopWatch(name, description string, scale time.Duration, scope promutils.Scope, opts ...MetricOption) StopWatch {
if len(metricKeys) == 0 {
panic(ErrNeverSet)
Expand Down
56 changes: 56 additions & 0 deletions promutils/labeled/summary.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package labeled

import (
"context"

"github.com/flyteorg/flytestdlib/contextutils"
"github.com/flyteorg/flytestdlib/promutils"
"github.com/prometheus/client_golang/prometheus"
)

// Summary represents a summary labeled with values from the context. See labeled.SetMetricsKeys for information about
// how to configure that.
type Summary struct {
*prometheus.SummaryVec

prometheus.Summary
additionalLabels []contextutils.Key
}

// Observe adds a single observation to the summary.
func (s Summary) Observe(ctx context.Context, v float64) {
summary, err := s.SummaryVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, s.additionalLabels...)...))
if err != nil {
panic(err.Error())
}
summary.Observe(v)

if s.Summary != nil {
s.Summary.Observe(v)
}
}

// NewSummary creates a new labeled summary. Label keys must be set before instantiating. If the unlabeled option is
// given, this object will also instantiate and emit another summary with the given name with an _unlabeled suffix.
// See labeled.SetMetricsKeys for information about how to configure that.
func NewSummary(name, description string, scope promutils.Scope, opts ...MetricOption) Summary {
if len(metricKeys) == 0 {
panic(ErrNeverSet)
}

s := Summary{}
for _, opt := range opts {
if _, emitUnlabeledMetric := opt.(EmitUnlabeledMetricOption); emitUnlabeledMetric {
s.Summary = scope.MustNewSummary(GetUnlabeledMetricName(name), description)
} else if additionalLabels, casted := opt.(AdditionalLabelsOption); casted {
s.SummaryVec = scope.MustNewSummaryVec(name, description, append(metricStringKeys, additionalLabels.Labels...)...)
s.additionalLabels = contextutils.MetricKeysFromStrings(additionalLabels.Labels)
}
}

if s.SummaryVec == nil {
s.SummaryVec = scope.MustNewSummaryVec(name, description, metricStringKeys...)
}

return s
}
127 changes: 127 additions & 0 deletions promutils/labeled/summary_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package labeled

import (
"context"
"strings"
"testing"

"github.com/flyteorg/flytestdlib/contextutils"
"github.com/flyteorg/flytestdlib/promutils"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
)

func TestLabeledSummary(t *testing.T) {
UnsetMetricKeys()
assert.NotPanics(t, func() {
SetMetricKeys(contextutils.ProjectKey, contextutils.DomainKey, contextutils.WorkflowIDKey, contextutils.TaskIDKey, contextutils.LaunchPlanIDKey)
})

t.Run("labeled", func(t *testing.T) {
scope := promutils.NewScope("testscope_summary")
ctx := context.Background()
ctx = contextutils.WithProjectDomain(ctx, "flyte", "dev")
s := NewSummary("unittest", "some desc", scope)
assert.NotNil(t, s)

s.Observe(ctx, 10)

const header = `
# HELP testscope_summary:unittest some desc
# TYPE testscope_summary:unittest summary
`
var expected = `
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.5"} 10
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.9"} 10
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.99"} 10
testscope_summary:unittest_sum{domain="dev",lp="",project="flyte",task="",wf=""} 10
testscope_summary:unittest_count{domain="dev",lp="",project="flyte",task="",wf=""} 1
`
err := testutil.CollectAndCompare(s.SummaryVec, strings.NewReader(header+expected))
assert.NoError(t, err)

s.Observe(ctx, 100)
s.Observe(ctx, 1000)

expected = `
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.5"} 100
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.9"} 1000
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.99"} 1000
testscope_summary:unittest_sum{domain="dev",lp="",project="flyte",task="",wf=""} 1110
testscope_summary:unittest_count{domain="dev",lp="",project="flyte",task="",wf=""} 3
`
err = testutil.CollectAndCompare(s.SummaryVec, strings.NewReader(header+expected))
assert.NoError(t, err)

s.Observe(contextutils.WithProjectDomain(ctx, "flyte", "prod"), 10)

expected = `
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.5"} 100
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.9"} 1000
testscope_summary:unittest{domain="dev",lp="",project="flyte",task="",wf="",quantile="0.99"} 1000
testscope_summary:unittest_sum{domain="dev",lp="",project="flyte",task="",wf=""} 1110
testscope_summary:unittest_count{domain="dev",lp="",project="flyte",task="",wf=""} 3
testscope_summary:unittest{domain="prod",lp="",project="flyte",task="",wf="",quantile="0.5"} 10
testscope_summary:unittest{domain="prod",lp="",project="flyte",task="",wf="",quantile="0.9"} 10
testscope_summary:unittest{domain="prod",lp="",project="flyte",task="",wf="",quantile="0.99"} 10
testscope_summary:unittest_sum{domain="prod",lp="",project="flyte",task="",wf=""} 10
testscope_summary:unittest_count{domain="prod",lp="",project="flyte",task="",wf=""} 1
`
err = testutil.CollectAndCompare(s.SummaryVec, strings.NewReader(header+expected))
assert.NoError(t, err)
})

t.Run("extra labels", func(t *testing.T) {
scope := promutils.NewScope("testscope_summary")
ctx := context.Background()
s := NewSummary("unittest2", "some desc", scope, AdditionalLabelsOption{Labels: []string{"method"}})
assert.NotNil(t, s)

methodKey := contextutils.Key("method")
s.Observe(context.WithValue(ctx, methodKey, "GET"), 10)
s.Observe(context.WithValue(ctx, methodKey, "POST"), 100)

const header = `
# HELP testscope_summary:unittest2 some desc
# TYPE testscope_summary:unittest2 summary
`
var expected = `
testscope_summary:unittest2{domain="",lp="",method="GET",project="",task="",wf="",quantile="0.5"} 10
testscope_summary:unittest2{domain="",lp="",method="GET",project="",task="",wf="",quantile="0.9"} 10
testscope_summary:unittest2{domain="",lp="",method="GET",project="",task="",wf="",quantile="0.99"} 10
testscope_summary:unittest2_sum{domain="",lp="",method="GET",project="",task="",wf=""} 10
testscope_summary:unittest2_count{domain="",lp="",method="GET",project="",task="",wf=""} 1
testscope_summary:unittest2{domain="",lp="",method="POST",project="",task="",wf="",quantile="0.5"} 100
testscope_summary:unittest2{domain="",lp="",method="POST",project="",task="",wf="",quantile="0.9"} 100
testscope_summary:unittest2{domain="",lp="",method="POST",project="",task="",wf="",quantile="0.99"} 100
testscope_summary:unittest2_sum{domain="",lp="",method="POST",project="",task="",wf=""} 100
testscope_summary:unittest2_count{domain="",lp="",method="POST",project="",task="",wf=""} 1
`
err := testutil.CollectAndCompare(s.SummaryVec, strings.NewReader(header+expected))
assert.NoError(t, err)
})

t.Run("unlabeled", func(t *testing.T) {
scope := promutils.NewScope("testscope_summary")
ctx := context.Background()
ctx = contextutils.WithProjectDomain(ctx, "flyte", "dev")
s := NewSummary("unittest3", "some desc", scope, EmitUnlabeledMetric)
assert.NotNil(t, s)

s.Observe(ctx, 10)

const header = `
# HELP testscope_summary:unittest3_unlabeled some desc
# TYPE testscope_summary:unittest3_unlabeled summary
`
var expected = `
testscope_summary:unittest3_unlabeled{quantile="0.5"} 10
testscope_summary:unittest3_unlabeled{quantile="0.9"} 10
testscope_summary:unittest3_unlabeled{quantile="0.99"} 10
testscope_summary:unittest3_unlabeled_sum 10
testscope_summary:unittest3_unlabeled_count 1
`
err := testutil.CollectAndCompare(s.Summary, strings.NewReader(header+expected))
assert.NoError(t, err)
})
}

0 comments on commit df5879c

Please sign in to comment.