Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Made sure summaries actually give output quantile objectives as well; improved flag docs and tests for complex type series calculation. #93

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions metrics/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ func (c *Collector) UpdateNotifyCh() chan struct{} {

type Config struct {
MetricCount, GaugeMetricCount, CounterMetricCount, HistogramMetricCount, NativeHistogramMetricCount, SummaryMetricCount int
HistogramBuckets int

HistogramBuckets, SummaryObjectives int

LabelCount, SeriesCount int
MaxSeriesCount, MinSeriesCount int
Expand All @@ -103,14 +104,16 @@ func NewConfigFromFlags(flagReg func(name, help string) *kingpin.FlagClause) *Co
IntVar(&cfg.GaugeMetricCount)
flagReg("counter-metric-count", "Number of counter metrics to serve.").Default("200").
IntVar(&cfg.CounterMetricCount)
flagReg("histogram-metric-count", "Number of explicit (classic) histogram metrics to serve.").Default("10").
flagReg("histogram-metric-count", "Number of explicit (classic) histogram metrics to serve. Use -histogram-metric-bucket-count to control number of buckets. Note that the overall number of series for a single classic histogram metric is equal to 2 (count and sum) + <histogram-metric-bucket-count> + 1 (+Inf bucket).").Default("10").
IntVar(&cfg.HistogramMetricCount)
flagReg("histogram-metric-bucket-count", "Number of explicit buckets (classic) histogram metrics.").Default("8").
flagReg("histogram-metric-bucket-count", "Number of explicit buckets (classic) histogram metrics, excluding +Inf bucket.").Default("7").
IntVar(&cfg.HistogramBuckets)
flagReg("native-histogram-metric-count", "Number of native (exponential) histogram metrics to serve.").Default("0").
IntVar(&cfg.NativeHistogramMetricCount)
flagReg("summary-metric-count", "Number of summary metrics to serve.").Default("0").
flagReg("summary-metric-count", "Number of summary metrics to serve. Use -summary-metric-objective-count to control number of quantile objectives. Note that the overall number of series for a single summary metric is equal to 2 (count and sum) + <summary-metric-objective-count>.").Default("0").
IntVar(&cfg.SummaryMetricCount)
flagReg("summary-metric-objective-count", "Number of objectives in the summary metrics to serve.").Default("2").
IntVar(&cfg.SummaryObjectives)

flagReg("label-count", "Number of labels per-metric.").Default("10").
IntVar(&cfg.LabelCount)
Expand Down Expand Up @@ -242,10 +245,22 @@ func (c *Collector) recreateMetrics(unsafeGetState readOnlyStateFn) {
c.nativeHistograms[id] = histogram
}

// Mimic some quantile objectives.
objectives := map[float64]float64{}
if c.cfg.SummaryObjectives > 0 {
parts := 100 / c.cfg.SummaryObjectives

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq: is it valid for summary objectives to be greater than 100?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they should be from 0.0 to 1.0 - you can see I am dividing by 100.0 later on. Using 100 to have cheap integer mitigation of float precision issues when substracting things later on (:

for i := 0; i < c.cfg.SummaryObjectives; i++ {
q := parts * (i + 1)
if q == 100 {
q = 99
}
objectives[float64(q)/100.0] = float64(100-q) / 1000.0
}
}
for id := range c.summaries {
mName := fmt.Sprintf("avalanche_summary_metric_%s_%v_%v", strings.Repeat("m", c.cfg.MetricLength), s.metricCycle, id)
summary := prometheus.NewSummaryVec(
prometheus.SummaryOpts{Name: mName, Help: help(mName)},
prometheus.SummaryOpts{Name: mName, Help: help(mName), Objectives: objectives},
append([]string{"series_id", "cycle_id"}, c.labelKeys...),
)
c.summaries[id] = summary
Expand Down
37 changes: 25 additions & 12 deletions metrics/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package metrics

import (
"fmt"
"math"
"strconv"
"testing"
"time"
Expand All @@ -40,6 +41,8 @@ func countSeries(t *testing.T, registry *prometheus.Registry) (seriesCount int)
return seriesCount
}

// countSeriesTypes gives exact count of all types. For complex types that are represented by counters in Prometheus
// data model (and text exposition formats), we count all individual resulting series.
func countSeriesTypes(t *testing.T, registry *prometheus.Registry) (gauges, counters, histograms, nhistograms, summaries int) {
t.Helper()

Expand All @@ -54,13 +57,20 @@ func countSeriesTypes(t *testing.T, registry *prometheus.Registry) (gauges, coun
case io_prometheus_client.MetricType_COUNTER:
counters++
case io_prometheus_client.MetricType_HISTOGRAM:
if len(m.GetHistogram().Bucket) == 0 {
if bkts := len(m.GetHistogram().Bucket); bkts == 0 {
nhistograms++
} else {
histograms++
histograms += 2 // count and sum.
histograms += len(m.GetHistogram().GetBucket())
if m.GetHistogram().GetBucket()[bkts-1].GetUpperBound() != math.Inf(+1) {
// In the proto model we don't put explicit +Inf bucket, unless there is an exemplar,
// but it will appear as series in text format and Prometheus model. Account for that.
histograms++
}
}
case io_prometheus_client.MetricType_SUMMARY:
summaries++
summaries += 2 // count and sum.
summaries += len(m.GetSummary().GetQuantile())
default:
t.Fatalf("unknown metric type found %v", mf.GetType())
}
Expand All @@ -74,9 +84,10 @@ func TestRunMetrics(t *testing.T) {
GaugeMetricCount: 200,
CounterMetricCount: 200,
HistogramMetricCount: 10,
HistogramBuckets: 8,
HistogramBuckets: 7,
NativeHistogramMetricCount: 10,
SummaryMetricCount: 10,
SummaryObjectives: 2,

MinSeriesCount: 0,
MaxSeriesCount: 1000,
Expand All @@ -102,19 +113,20 @@ func TestRunMetrics(t *testing.T) {
g, c, h, nh, s := countSeriesTypes(t, reg)
assert.Equal(t, testCfg.GaugeMetricCount*testCfg.SeriesCount, g)
assert.Equal(t, testCfg.CounterMetricCount*testCfg.SeriesCount, c)
assert.Equal(t, testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, (2+testCfg.HistogramBuckets+1)*testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, testCfg.NativeHistogramMetricCount*testCfg.SeriesCount, nh)
assert.Equal(t, testCfg.SummaryMetricCount*testCfg.SeriesCount, s)
assert.Equal(t, (2+testCfg.SummaryObjectives)*testCfg.SummaryMetricCount*testCfg.SeriesCount, s)
}

func TestRunMetrics_ValueChange_SeriesCountSame(t *testing.T) {
testCfg := Config{
GaugeMetricCount: 200,
CounterMetricCount: 200,
HistogramMetricCount: 10,
HistogramBuckets: 8,
HistogramBuckets: 7,
NativeHistogramMetricCount: 10,
SummaryMetricCount: 10,
SummaryObjectives: 2,

MinSeriesCount: 0,
MaxSeriesCount: 1000,
Expand Down Expand Up @@ -145,9 +157,9 @@ func TestRunMetrics_ValueChange_SeriesCountSame(t *testing.T) {
g, c, h, nh, s := countSeriesTypes(t, reg)
assert.Equal(t, testCfg.GaugeMetricCount*testCfg.SeriesCount, g)
assert.Equal(t, testCfg.CounterMetricCount*testCfg.SeriesCount, c)
assert.Equal(t, testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, (2+testCfg.HistogramBuckets+1)*testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, testCfg.NativeHistogramMetricCount*testCfg.SeriesCount, nh)
assert.Equal(t, testCfg.SummaryMetricCount*testCfg.SeriesCount, s)
assert.Equal(t, (2+testCfg.SummaryObjectives)*testCfg.SummaryMetricCount*testCfg.SeriesCount, s)
}
}

Expand Down Expand Up @@ -184,9 +196,10 @@ func TestRunMetrics_SeriesChurn(t *testing.T) {
GaugeMetricCount: 200,
CounterMetricCount: 200,
HistogramMetricCount: 10,
HistogramBuckets: 8,
HistogramBuckets: 7,
NativeHistogramMetricCount: 10,
SummaryMetricCount: 10,
SummaryObjectives: 2,

MinSeriesCount: 0,
MaxSeriesCount: 1000,
Expand Down Expand Up @@ -220,9 +233,9 @@ func TestRunMetrics_SeriesChurn(t *testing.T) {
g, c, h, nh, s := countSeriesTypes(t, reg)
assert.Equal(t, testCfg.GaugeMetricCount*testCfg.SeriesCount, g)
assert.Equal(t, testCfg.CounterMetricCount*testCfg.SeriesCount, c)
assert.Equal(t, testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, (2+testCfg.HistogramBuckets+1)*testCfg.HistogramMetricCount*testCfg.SeriesCount, h)
assert.Equal(t, testCfg.NativeHistogramMetricCount*testCfg.SeriesCount, nh)
assert.Equal(t, testCfg.SummaryMetricCount*testCfg.SeriesCount, s)
assert.Equal(t, (2+testCfg.SummaryObjectives)*testCfg.SummaryMetricCount*testCfg.SeriesCount, s)

gotCycleID := currentCycleID(t, reg)
require.Greater(t, gotCycleID, cycleID)
Expand Down
Loading