Skip to content

Commit

Permalink
feat: Made sure summaries actually give output quantile objectives as…
Browse files Browse the repository at this point in the history
… well; improved flag docs and tests for complex type series calculation. (#93)

Signed-off-by: bwplotka <[email protected]>
  • Loading branch information
bwplotka authored Oct 2, 2024
1 parent 9b0a010 commit 5bc0599
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
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
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

0 comments on commit 5bc0599

Please sign in to comment.