create sub-hierarchies for summary and histogram options

Currently the Buckets and Quantiles settings are top level settings per metric
in the yaml.  In a subsequent commit we're going to allow adding more such
options for summaries, at which point having them all at the top level gets
confusing.

Split the options out into separate hierarchies to allow adding more options,
without adding confusion.  We preserve backwards compatibility by still
accepting the old option, but warning when it is present.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
This commit is contained in:
Thomas Gummerer 2020-01-16 16:55:09 +00:00
parent c9c23a4f9e
commit 80b77513a6
4 changed files with 148 additions and 39 deletions

View file

@ -247,6 +247,7 @@ mappings:
provider: "$2"
outcome: "$3"
job: "${1}_server"
summary_options:
quantiles:
- quantile: 0.99
error: 0.001
@ -268,6 +269,7 @@ to set the timer type for a single metric:
mappings:
- match: "test.timing.*.*.*"
timer_type: histogram
histogram_options:
buckets: [ 0.01, 0.025, 0.05, 0.1 ]
name: "my_timer"
labels:

View file

@ -65,13 +65,23 @@ type MetricMapping struct {
labelKeys []string
labelFormatters []*fsm.TemplateFormatter
TimerType TimerType `yaml:"timer_type"`
Buckets []float64 `yaml:"buckets"`
Quantiles []metricObjective `yaml:"quantiles"`
LegacyBuckets []float64 `yaml:"buckets"`
LegacyQuantiles []metricObjective `yaml:"quantiles"`
MatchType MatchType `yaml:"match_type"`
HelpText string `yaml:"help"`
Action ActionType `yaml:"action"`
MatchMetricType MetricType `yaml:"match_metric_type"`
Ttl time.Duration `yaml:"ttl"`
SummaryOptions *SummaryOptions `yaml:"summary_options"`
HistogramOptions *HistogramOptions `yaml:"histogram_options"`
}
type SummaryOptions struct {
Quantiles []metricObjective `yaml:"quantiles"`
}
type HistogramOptions struct {
Buckets []float64 `yaml:"buckets"`
}
type metricObjective struct {
@ -172,12 +182,60 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int) er
currentMapping.TimerType = n.Defaults.TimerType
}
if currentMapping.Buckets == nil || len(currentMapping.Buckets) == 0 {
currentMapping.Buckets = n.Defaults.Buckets
if currentMapping.LegacyQuantiles != nil &&
(currentMapping.SummaryOptions == nil || currentMapping.SummaryOptions.Quantiles != nil) {
log.Warn("using the top level quantiles is deprecated. Please use quantiles in the summary_options hierarchy")
}
if currentMapping.Quantiles == nil || len(currentMapping.Quantiles) == 0 {
currentMapping.Quantiles = n.Defaults.Quantiles
if currentMapping.LegacyBuckets != nil &&
(currentMapping.HistogramOptions == nil || currentMapping.HistogramOptions.Buckets != nil) {
log.Warn("using the top level buckets is deprecated. Please use buckets in the histogram_options hierarchy")
}
if currentMapping.SummaryOptions != nil &&
currentMapping.LegacyQuantiles != nil &&
currentMapping.SummaryOptions.Quantiles != nil {
return fmt.Errorf("cannot use quantiles in both the top level and summary options at the same time in %s", currentMapping.Match)
}
if currentMapping.HistogramOptions != nil &&
currentMapping.LegacyBuckets != nil &&
currentMapping.HistogramOptions.Buckets != nil {
return fmt.Errorf("cannot use buckets in both the top level and histogram options at the same time in %s", currentMapping.Match)
}
if currentMapping.TimerType == TimerTypeHistogram {
if currentMapping.SummaryOptions != nil {
return fmt.Errorf("cannot use histogram timer and summary options at the same time")
}
if currentMapping.HistogramOptions == nil {
currentMapping.HistogramOptions = &HistogramOptions{}
}
if currentMapping.LegacyBuckets != nil && len(currentMapping.LegacyBuckets) != 0 {
currentMapping.HistogramOptions.Buckets = currentMapping.LegacyBuckets
}
if currentMapping.HistogramOptions.Buckets == nil || len(currentMapping.HistogramOptions.Buckets) == 0 {
currentMapping.HistogramOptions.Buckets = n.Defaults.Buckets
}
}
if currentMapping.TimerType == TimerTypeSummary {
if currentMapping.HistogramOptions != nil {
return fmt.Errorf("cannot use summary timer and histogram options at the same time")
}
if currentMapping.SummaryOptions == nil {
currentMapping.SummaryOptions = &SummaryOptions{}
}
}
if currentMapping.LegacyQuantiles == nil || len(currentMapping.LegacyQuantiles) == 0 {
currentMapping.LegacyQuantiles = n.Defaults.Quantiles
if currentMapping.LegacyQuantiles != nil && len(currentMapping.LegacyQuantiles) != 0 {
currentMapping.SummaryOptions.Quantiles = currentMapping.LegacyQuantiles
}
if currentMapping.SummaryOptions.Quantiles == nil || len(currentMapping.SummaryOptions.Quantiles) == 0 {
currentMapping.SummaryOptions.Quantiles = n.Defaults.Quantiles
}
}
if currentMapping.Ttl == 0 && n.Defaults.Ttl > 0 {

View file

@ -493,6 +493,51 @@ mappings:
timer_type: wrong
name: "foo"
labels: {}
`,
configBad: true,
},
// new style quantiles
{
config: `---
mappings:
- match: test.*.*
timer_type: summary
name: "foo"
labels: {}
summary_options:
quantiles:
- quantile: 0.42
error: 0.04
- quantile: 0.7
error: 0.002
`,
mappings: mappings{
{
statsdMetric: "test.*.*",
name: "foo",
labels: map[string]string{},
quantiles: []metricObjective{
{Quantile: 0.42, Error: 0.04},
{Quantile: 0.7, Error: 0.002},
},
},
},
},
// duplicate quantiles are bad
{
config: `---
mappings:
- match: test.*.*
timer_type: summary
name: "foo"
labels: {}
quantiles:
- quantile: 0.42
error: 0.04
summary_options:
quantiles:
- quantile: 0.42
error: 0.04
`,
configBad: true,
},
@ -777,15 +822,15 @@ mappings:
}
if len(mapping.quantiles) != 0 {
if len(mapping.quantiles) != len(m.Quantiles) {
t.Fatalf("%d.%q: Expected %d quantiles, got %d", i, metric, len(mapping.quantiles), len(m.Quantiles))
if len(mapping.quantiles) != len(m.SummaryOptions.Quantiles) {
t.Fatalf("%d.%q: Expected %d quantiles, got %d", i, metric, len(mapping.quantiles), len(m.SummaryOptions.Quantiles))
}
for i, quantile := range mapping.quantiles {
if quantile.Quantile != m.Quantiles[i].Quantile {
t.Fatalf("%d.%q: Expected quantile %v, got %v", i, metric, m.Quantiles[i].Quantile, quantile.Quantile)
if quantile.Quantile != m.SummaryOptions.Quantiles[i].Quantile {
t.Fatalf("%d.%q: Expected quantile %v, got %v", i, metric, m.SummaryOptions.Quantiles[i].Quantile, quantile.Quantile)
}
if quantile.Error != m.Quantiles[i].Error {
t.Fatalf("%d.%q: Expected Error margin %v, got %v", i, metric, m.Quantiles[i].Error, quantile.Error)
if quantile.Error != m.SummaryOptions.Quantiles[i].Error {
t.Fatalf("%d.%q: Expected Error margin %v, got %v", i, metric, m.SummaryOptions.Quantiles[i].Error, quantile.Error)
}
}
}

View file

@ -278,8 +278,8 @@ func (r *registry) getHistogram(metricName string, labels prometheus.Labels, hel
if vh == nil {
metricsCount.WithLabelValues("histogram").Inc()
buckets := r.mapper.Defaults.Buckets
if mapping.Buckets != nil && len(mapping.Buckets) > 0 {
buckets = mapping.Buckets
if mapping.HistogramOptions != nil && len(mapping.HistogramOptions.Buckets) > 0 {
buckets = mapping.HistogramOptions.Buckets
}
histogramVec = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: metricName,
@ -325,8 +325,12 @@ func (r *registry) getSummary(metricName string, labels prometheus.Labels, help
if vh == nil {
metricsCount.WithLabelValues("summary").Inc()
quantiles := r.mapper.Defaults.Quantiles
if mapping != nil && mapping.Quantiles != nil && len(mapping.Quantiles) > 0 {
quantiles = mapping.Quantiles
if mapping != nil && mapping.SummaryOptions != nil && len(mapping.SummaryOptions.Quantiles) > 0 {
quantiles = mapping.SummaryOptions.Quantiles
}
summaryOptions := mapper.SummaryOptions{}
if mapping != nil && mapping.SummaryOptions != nil {
summaryOptions = *mapping.SummaryOptions
}
objectives := make(map[float64]float64)
for _, q := range quantiles {