forked from mirrors/statsd_exporter
add support for setting histogram_options and summary_options in defaults
Signed-off-by: glightfoot <glightfoot@rsglab.com>
This commit is contained in:
parent
64dd103e3f
commit
06411336c7
5 changed files with 650 additions and 130 deletions
28
README.md
28
README.md
|
@ -341,9 +341,9 @@ mappings:
|
|||
error: 0.05
|
||||
- quantile: 0.5
|
||||
error: 0.005
|
||||
max_summary_age: 30s
|
||||
summary_age_buckets: 3
|
||||
stream_buffer_size: 1000
|
||||
max_age: 30s
|
||||
age_buckets: 3
|
||||
buf_cap: 1000
|
||||
```
|
||||
|
||||
The default quantiles are 0.99, 0.9, and 0.5.
|
||||
|
@ -414,16 +414,34 @@ mappings:
|
|||
|
||||
### Global defaults
|
||||
|
||||
One may also set defaults for the observer type, buckets or quantiles, and match type.
|
||||
One may also set defaults for the observer type, histogram options, summary options, and match type.
|
||||
These will be used by all mappings that do not define them.
|
||||
|
||||
An option that can only be configured in `defaults` is `glob_disable_ordering`, which is `false` if omitted.
|
||||
By setting this to `true`, `glob` match type will not honor the occurance of rules in the mapping rules file and always treat `*` as lower priority than a concrete string.
|
||||
|
||||
Setting `buckets` or `quantiles` in the defaults is deprecated in favor of `histogram_options` and `summary_options`, which will override the deprecated values.
|
||||
|
||||
If `summary_options` is present in a mapping config, it will only override the fields set in the mapping. Unset fields in the mapping will take the values from the defaults.
|
||||
|
||||
```yaml
|
||||
defaults:
|
||||
observer_type: histogram
|
||||
histogram_options:
|
||||
buckets: [.005, .01, .025, .05, .1, .25, .5, 1, 2.5 ]
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.99
|
||||
error: 0.001
|
||||
- quantile: 0.95
|
||||
error: 0.01
|
||||
- quantile: 0.9
|
||||
error: 0.05
|
||||
- quantile: 0.5
|
||||
error: 0.005
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
match_type: glob
|
||||
glob_disable_ordering: false
|
||||
ttl: 0 # metrics do not expire
|
||||
|
@ -435,7 +453,7 @@ mappings:
|
|||
provider: "$2"
|
||||
outcome: "$3"
|
||||
job: "${1}_server"
|
||||
# This will be a summary timer.
|
||||
# This will be a summary using the summary_options set in `defaults`
|
||||
- match: "other.distribution.*.*.*"
|
||||
observer_type: summary
|
||||
name: "other_distribution"
|
||||
|
|
|
@ -22,8 +22,9 @@ import (
|
|||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/log"
|
||||
"github.com/prometheus/statsd_exporter/pkg/mapper/fsm"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/prometheus/statsd_exporter/pkg/mapper/fsm"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -77,12 +78,12 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
|||
return err
|
||||
}
|
||||
|
||||
if n.Defaults.Buckets == nil || len(n.Defaults.Buckets) == 0 {
|
||||
n.Defaults.Buckets = prometheus.DefBuckets
|
||||
if len(n.Defaults.HistogramOptions.Buckets) == 0 {
|
||||
n.Defaults.HistogramOptions.Buckets = prometheus.DefBuckets
|
||||
}
|
||||
|
||||
if n.Defaults.Quantiles == nil || len(n.Defaults.Quantiles) == 0 {
|
||||
n.Defaults.Quantiles = defaultQuantiles
|
||||
if len(n.Defaults.SummaryOptions.Quantiles) == 0 {
|
||||
n.Defaults.SummaryOptions.Quantiles = defaultQuantiles
|
||||
}
|
||||
|
||||
if n.Defaults.MatchType == MatchTypeDefault {
|
||||
|
@ -190,7 +191,7 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
|||
currentMapping.HistogramOptions.Buckets = currentMapping.LegacyBuckets
|
||||
}
|
||||
if currentMapping.HistogramOptions.Buckets == nil || len(currentMapping.HistogramOptions.Buckets) == 0 {
|
||||
currentMapping.HistogramOptions.Buckets = n.Defaults.Buckets
|
||||
currentMapping.HistogramOptions.Buckets = n.Defaults.HistogramOptions.Buckets
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +206,16 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string, cacheSize int, op
|
|||
currentMapping.SummaryOptions.Quantiles = currentMapping.LegacyQuantiles
|
||||
}
|
||||
if currentMapping.SummaryOptions.Quantiles == nil || len(currentMapping.SummaryOptions.Quantiles) == 0 {
|
||||
currentMapping.SummaryOptions.Quantiles = n.Defaults.Quantiles
|
||||
currentMapping.SummaryOptions.Quantiles = n.Defaults.SummaryOptions.Quantiles
|
||||
}
|
||||
if currentMapping.SummaryOptions.MaxAge == 0 {
|
||||
currentMapping.SummaryOptions.MaxAge = n.Defaults.SummaryOptions.MaxAge
|
||||
}
|
||||
if currentMapping.SummaryOptions.AgeBuckets == 0 {
|
||||
currentMapping.SummaryOptions.AgeBuckets = n.Defaults.SummaryOptions.AgeBuckets
|
||||
}
|
||||
if currentMapping.SummaryOptions.BufCap == 0 {
|
||||
currentMapping.SummaryOptions.BufCap = n.Defaults.SummaryOptions.BufCap
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@ import "time"
|
|||
type mapperConfigDefaults struct {
|
||||
ObserverType ObserverType `yaml:"observer_type"`
|
||||
TimerType ObserverType `yaml:"timer_type,omitempty"` // DEPRECATED - field only present to preserve backwards compatibility in configs. Always empty
|
||||
Buckets []float64 `yaml:"buckets"`
|
||||
Quantiles []metricObjective `yaml:"quantiles"`
|
||||
Buckets []float64 `yaml:"buckets"` // DEPRECATED - field only present to preserve backwards compatibility in configs. Always empty
|
||||
Quantiles []metricObjective `yaml:"quantiles"` // DEPRECATED - field only present to preserve backwards compatibility in configs. Always empty
|
||||
MatchType MatchType `yaml:"match_type"`
|
||||
GlobDisableOrdering bool `yaml:"glob_disable_ordering"`
|
||||
Ttl time.Duration `yaml:"ttl"`
|
||||
SummaryOptions SummaryOptions `yaml:"summary_options"`
|
||||
HistogramOptions HistogramOptions `yaml:"histogram_options"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML is a custom unmarshal function to allow use of deprecated config keys
|
||||
|
@ -36,16 +38,26 @@ func (d *mapperConfigDefaults) UnmarshalYAML(unmarshal func(interface{}) error)
|
|||
|
||||
// Copy defaults
|
||||
d.ObserverType = tmp.ObserverType
|
||||
d.Buckets = tmp.Buckets
|
||||
d.Quantiles = tmp.Quantiles
|
||||
d.MatchType = tmp.MatchType
|
||||
d.GlobDisableOrdering = tmp.GlobDisableOrdering
|
||||
d.Ttl = tmp.Ttl
|
||||
d.SummaryOptions = tmp.SummaryOptions
|
||||
d.HistogramOptions = tmp.HistogramOptions
|
||||
|
||||
// Use deprecated TimerType if necessary
|
||||
if tmp.ObserverType == "" {
|
||||
d.ObserverType = tmp.TimerType
|
||||
}
|
||||
|
||||
// Use deprecated quantiles if necessary
|
||||
if len(tmp.SummaryOptions.Quantiles) == 0 && len(tmp.Quantiles) > 0 {
|
||||
d.SummaryOptions = SummaryOptions{Quantiles: tmp.Quantiles}
|
||||
}
|
||||
|
||||
// Use deprecated buckets if necessary
|
||||
if len(tmp.HistogramOptions.Buckets) == 0 && len(tmp.Buckets) > 0 {
|
||||
d.HistogramOptions = HistogramOptions{Buckets: tmp.Buckets}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ package mapper
|
|||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
type mappings []struct {
|
||||
|
@ -29,18 +31,21 @@ type mappings []struct {
|
|||
maxAge time.Duration
|
||||
ageBuckets uint32
|
||||
bufCap uint32
|
||||
buckets []float64
|
||||
}
|
||||
|
||||
func TestMetricMapperYAML(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
testName string
|
||||
config string
|
||||
configBad bool
|
||||
mappings mappings
|
||||
}{
|
||||
// Empty config.
|
||||
{},
|
||||
// Config with several mapping definitions.
|
||||
{
|
||||
testName: "Empty config",
|
||||
},
|
||||
{
|
||||
testName: "Config with several mapping definitions",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.dispatcher.*.*.*
|
||||
|
@ -153,8 +158,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
//Config with backtracking
|
||||
{
|
||||
testName: "Config with backtracking",
|
||||
config: `
|
||||
defaults:
|
||||
glob_disable_ordering: true
|
||||
|
@ -198,6 +203,7 @@ mappings:
|
|||
// This test case makes sure the captures in the non-matched later rule
|
||||
// doesn't affect the captures in the first matched rule.
|
||||
{
|
||||
testName: "Config with backtracking, the non-matched rule has star(s)",
|
||||
config: `
|
||||
defaults:
|
||||
glob_disable_ordering: false
|
||||
|
@ -232,8 +238,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
//Config with super sets, disables ordering
|
||||
{
|
||||
testName: "Config with super sets, disables ordering",
|
||||
config: `
|
||||
defaults:
|
||||
glob_disable_ordering: true
|
||||
|
@ -268,8 +274,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
//Config with super sets, keeps ordering
|
||||
{
|
||||
testName: "Config with super sets, keeps ordering",
|
||||
config: `
|
||||
defaults:
|
||||
glob_disable_ordering: false
|
||||
|
@ -293,8 +299,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with bad regex reference.
|
||||
{
|
||||
testName: "Config with bad regex reference",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*
|
||||
|
@ -312,8 +318,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with good regex reference.
|
||||
{
|
||||
testName: "Config with good regex reference",
|
||||
config: `
|
||||
mappings:
|
||||
- match: test.*
|
||||
|
@ -331,8 +337,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with bad metric line.
|
||||
{
|
||||
testName: "Config with bad metric line",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: bad--metric-line.*.*
|
||||
|
@ -341,8 +347,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with dynamic metric name.
|
||||
{
|
||||
testName: "Config with dynamic metric name",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test1.*.*
|
||||
|
@ -371,8 +377,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with bad metric name.
|
||||
{
|
||||
testName: "Config with bad metric name",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -381,8 +387,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with no metric name.
|
||||
{
|
||||
testName: "Config with no metric name",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -391,13 +397,13 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with no mappings.
|
||||
{
|
||||
testName: "Config with no mappings",
|
||||
config: ``,
|
||||
mappings: mappings{},
|
||||
},
|
||||
// Config without a trailing newline.
|
||||
{
|
||||
testName: "Config without a trailing newline",
|
||||
config: `mappings:
|
||||
- match: test.*
|
||||
name: "name"
|
||||
|
@ -413,8 +419,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with an improperly escaped *.
|
||||
{
|
||||
testName: "Config with an improperly escaped *",
|
||||
config: `
|
||||
mappings:
|
||||
- match: *.test.*
|
||||
|
@ -423,8 +429,8 @@ mappings:
|
|||
label: "${1}_foo"`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with a properly escaped *.
|
||||
{
|
||||
testName: "Config with a properly escaped *",
|
||||
config: `
|
||||
mappings:
|
||||
- match: "*.test.*"
|
||||
|
@ -441,8 +447,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with good observer type.
|
||||
{
|
||||
testName: "Config with good observer type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -467,8 +473,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with good observer type and unused timer type
|
||||
{
|
||||
testName: "Config with good observer type and unused timer type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -495,6 +501,7 @@ mappings:
|
|||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with good observertype and no defaults",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test1.*.*
|
||||
|
@ -515,8 +522,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with good deprecated timer type
|
||||
{
|
||||
testName: "Config with good deprecated timer type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test1.*.*
|
||||
|
@ -537,8 +544,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with bad observer type.
|
||||
{
|
||||
testName: "Config with bad observer type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -548,8 +555,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with bad deprecated timer type.
|
||||
{
|
||||
testName: "Config with bad deprecated timer type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -559,8 +566,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// new style quantiles
|
||||
{
|
||||
testName: "New style quantiles",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -586,8 +593,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config with summary configuration.
|
||||
{
|
||||
testName: "Config with summary options",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -619,8 +626,457 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// duplicate quantiles are bad
|
||||
{
|
||||
testName: "Config with default summary options",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.42
|
||||
error: 0.04
|
||||
- quantile: 0.7
|
||||
error: 0.002
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.42, Error: 0.04},
|
||||
{Quantile: 0.7, Error: 0.002},
|
||||
},
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 2,
|
||||
bufCap: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with default summary options without quantiles",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: defaultQuantiles,
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 2,
|
||||
bufCap: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with default summary options overrides quantiles",
|
||||
config: `---
|
||||
defaults:
|
||||
quantiles:
|
||||
- quantile: 0.9
|
||||
error: 0.1
|
||||
- quantile: 0.99
|
||||
error: 0.01
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.42
|
||||
error: 0.04
|
||||
- quantile: 0.7
|
||||
error: 0.002
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.42, Error: 0.04},
|
||||
{Quantile: 0.7, Error: 0.002},
|
||||
},
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 2,
|
||||
bufCap: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that overrides default summary options",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.042
|
||||
error: 0.4
|
||||
- quantile: 0.07
|
||||
error: 0.02
|
||||
max_age: 15m
|
||||
age_buckets: 3
|
||||
buf_cap: 100
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.42
|
||||
error: 0.04
|
||||
- quantile: 0.7
|
||||
error: 0.002
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.42, Error: 0.04},
|
||||
{Quantile: 0.7, Error: 0.002},
|
||||
},
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 2,
|
||||
bufCap: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that overrides default summary options and a default options mapping",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.9
|
||||
error: 0.1
|
||||
- quantile: 0.99
|
||||
error: 0.01
|
||||
max_age: 15m
|
||||
age_buckets: 3
|
||||
buf_cap: 100
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.42
|
||||
error: 0.04
|
||||
- quantile: 0.7
|
||||
error: 0.002
|
||||
max_age: 5m
|
||||
age_buckets: 2
|
||||
buf_cap: 1000
|
||||
- match: test_default.*.*
|
||||
observer_type: summary
|
||||
name: "foo_default"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.42, Error: 0.04},
|
||||
{Quantile: 0.7, Error: 0.002},
|
||||
},
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 2,
|
||||
bufCap: 1000,
|
||||
},
|
||||
{
|
||||
statsdMetric: "test_default.*.*",
|
||||
name: "foo_default",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.9, Error: 0.1},
|
||||
{Quantile: 0.99, Error: 0.01},
|
||||
},
|
||||
maxAge: 15 * time.Minute,
|
||||
ageBuckets: 3,
|
||||
bufCap: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that partially overrides default summary quantiles and a default options mapping",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.9
|
||||
error: 0.1
|
||||
- quantile: 0.99
|
||||
error: 0.01
|
||||
max_age: 15m
|
||||
age_buckets: 3
|
||||
buf_cap: 100
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.42
|
||||
error: 0.04
|
||||
- quantile: 0.7
|
||||
error: 0.002
|
||||
- match: test_default.*.*
|
||||
observer_type: summary
|
||||
name: "foo_default"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.42, Error: 0.04},
|
||||
{Quantile: 0.7, Error: 0.002},
|
||||
},
|
||||
maxAge: 15 * time.Minute,
|
||||
ageBuckets: 3,
|
||||
bufCap: 100,
|
||||
},
|
||||
{
|
||||
statsdMetric: "test_default.*.*",
|
||||
name: "foo_default",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.9, Error: 0.1},
|
||||
{Quantile: 0.99, Error: 0.01},
|
||||
},
|
||||
maxAge: 15 * time.Minute,
|
||||
ageBuckets: 3,
|
||||
bufCap: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that partially overrides default summary max_age and a default options mapping",
|
||||
config: `---
|
||||
defaults:
|
||||
summary_options:
|
||||
quantiles:
|
||||
- quantile: 0.9
|
||||
error: 0.1
|
||||
- quantile: 0.99
|
||||
error: 0.01
|
||||
max_age: 15m
|
||||
age_buckets: 3
|
||||
buf_cap: 100
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: summary
|
||||
name: "foo"
|
||||
labels: {}
|
||||
summary_options:
|
||||
max_age: 5m
|
||||
- match: test_default.*.*
|
||||
observer_type: summary
|
||||
name: "foo_default"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.9, Error: 0.1},
|
||||
{Quantile: 0.99, Error: 0.01},
|
||||
},
|
||||
maxAge: 5 * time.Minute,
|
||||
ageBuckets: 3,
|
||||
bufCap: 100,
|
||||
},
|
||||
{
|
||||
statsdMetric: "test_default.*.*",
|
||||
name: "foo_default",
|
||||
labels: map[string]string{},
|
||||
quantiles: []metricObjective{
|
||||
{Quantile: 0.9, Error: 0.1},
|
||||
{Quantile: 0.99, Error: 0.01},
|
||||
},
|
||||
maxAge: 15 * time.Minute,
|
||||
ageBuckets: 3,
|
||||
bufCap: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with histogram options",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
histogram_options:
|
||||
buckets: [0.1, 1, 10, 100, 1000]
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with default histogram options",
|
||||
config: `---
|
||||
defaults:
|
||||
histogram_options:
|
||||
buckets: [0.1, 1, 10, 100, 1000]
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with default histogram options without buckets",
|
||||
config: `---
|
||||
defaults:
|
||||
histogram_options:
|
||||
buckets: []
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: prometheus.DefBuckets,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config with default histogram options overrides buckets",
|
||||
config: `---
|
||||
defaults:
|
||||
buckets: [0.2, 2, 20, 200, 2000]
|
||||
histogram_options:
|
||||
buckets: [0.1, 1, 10, 100, 1000]
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that overrides default histogram configuration",
|
||||
config: `---
|
||||
defaults:
|
||||
histogram_options:
|
||||
buckets: [0.2, 2, 20, 200, 2000]
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
histogram_options:
|
||||
buckets: [0.1, 1, 10, 100, 1000]
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Config that overrides default histogram configuration and a default options mapping",
|
||||
config: `---
|
||||
defaults:
|
||||
histogram_options:
|
||||
buckets: [0.2, 2, 20, 200]
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
observer_type: histogram
|
||||
name: "foo"
|
||||
labels: {}
|
||||
histogram_options:
|
||||
buckets: [0.1, 1, 10, 100, 1000]
|
||||
- match: test_default.*.*
|
||||
observer_type: histogram
|
||||
name: "foo_default"
|
||||
labels: {}
|
||||
`,
|
||||
mappings: mappings{
|
||||
{
|
||||
statsdMetric: "test.*.*",
|
||||
name: "foo",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.1, 1, 10, 100, 1000},
|
||||
},
|
||||
{
|
||||
statsdMetric: "test_default.*.*",
|
||||
name: "foo_default",
|
||||
labels: map[string]string{},
|
||||
buckets: []float64{0.2, 2, 20, 200},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "Duplicate quantiles are bad",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -637,8 +1093,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with good metric type.
|
||||
{
|
||||
testName: "Config with good metric type",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -647,8 +1103,8 @@ mappings:
|
|||
labels: {}
|
||||
`,
|
||||
},
|
||||
// Config with good metric type observer.
|
||||
{
|
||||
testName: "Config with good metric type observer",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -657,8 +1113,8 @@ mappings:
|
|||
labels: {}
|
||||
`,
|
||||
},
|
||||
// Config with good metric type timer.
|
||||
{
|
||||
testName: "Config with good metric type timer",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -667,8 +1123,8 @@ mappings:
|
|||
labels: {}
|
||||
`,
|
||||
},
|
||||
// Config with bad metric type matcher.
|
||||
{
|
||||
testName: "Config with bad metric type matcher",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -678,8 +1134,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
// Config with multiple explicit metric types
|
||||
{
|
||||
testName: "Config with multiple explicit metric types",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.foo.*
|
||||
|
@ -702,8 +1158,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
//Config with uncompilable regex.
|
||||
{
|
||||
testName: "Config with uncompilable regex",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: "*\\.foo"
|
||||
|
@ -713,8 +1169,8 @@ mappings:
|
|||
`,
|
||||
configBad: true,
|
||||
},
|
||||
//Config with non-matched metric.
|
||||
{
|
||||
testName: "Config with non-matched metric",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: foo.*.*
|
||||
|
@ -731,8 +1187,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
//Config with no name.
|
||||
{
|
||||
testName: "Config with no name",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: *\.foo
|
||||
|
@ -743,6 +1199,7 @@ mappings:
|
|||
configBad: true,
|
||||
},
|
||||
{
|
||||
testName: "Config with labels from glob",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: p.*.*.c.*
|
||||
|
@ -765,8 +1222,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Example from the README.
|
||||
{
|
||||
testName: "Example from the README",
|
||||
config: `
|
||||
mappings:
|
||||
- match: test.dispatcher.*.*.*
|
||||
|
@ -810,8 +1267,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config that drops all.
|
||||
{
|
||||
testName: "Config that drops all",
|
||||
config: `mappings:
|
||||
- match: .
|
||||
match_type: regex
|
||||
|
@ -826,8 +1283,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config that has a catch-all to drop all.
|
||||
{
|
||||
testName: "Config that has a catch-all to drop all",
|
||||
config: `mappings:
|
||||
- match: web.*
|
||||
name: "web"
|
||||
|
@ -850,8 +1307,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config that has a ttl.
|
||||
{
|
||||
testName: "Config that has a ttl",
|
||||
config: `mappings:
|
||||
- match: web.*
|
||||
name: "web"
|
||||
|
@ -872,8 +1329,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config that has a default ttl.
|
||||
{
|
||||
testName: "Config that has a default ttl",
|
||||
config: `defaults:
|
||||
ttl: 1m2s
|
||||
mappings:
|
||||
|
@ -895,8 +1352,8 @@ mappings:
|
|||
},
|
||||
},
|
||||
},
|
||||
// Config that override a default ttl.
|
||||
{
|
||||
testName: "Config that override a default ttl",
|
||||
config: `defaults:
|
||||
ttl: 1m2s
|
||||
mappings:
|
||||
|
@ -923,6 +1380,10 @@ mappings:
|
|||
|
||||
mapper := MetricMapper{}
|
||||
for i, scenario := range scenarios {
|
||||
if scenario.testName == "" {
|
||||
t.Fatalf("Missing testName in scenario %+v", scenario)
|
||||
}
|
||||
t.Run(scenario.testName, func(t *testing.T) {
|
||||
err := mapper.InitFromYAMLString(scenario.config, 1000)
|
||||
if err != nil && !scenario.configBad {
|
||||
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
||||
|
@ -960,6 +1421,17 @@ mappings:
|
|||
t.Fatalf("%d.%q: Expected match metric of %s, got %s", i, metric, mapType, m.MatchMetricType)
|
||||
}
|
||||
|
||||
if len(mapping.buckets) != 0 {
|
||||
if len(mapping.buckets) != len(m.HistogramOptions.Buckets) {
|
||||
t.Fatalf("%d.%q: Expected %d buckets, got %d", i, metric, len(mapping.buckets), len(m.HistogramOptions.Buckets))
|
||||
}
|
||||
for i, bucket := range mapping.buckets {
|
||||
if bucket != m.HistogramOptions.Buckets[i] {
|
||||
t.Fatalf("%d.%q: Expected bucket %v, got %v", i, metric, m.HistogramOptions.Buckets[i], bucket)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(mapping.quantiles) != 0 {
|
||||
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))
|
||||
|
@ -983,17 +1455,19 @@ mappings:
|
|||
t.Fatalf("%d.%q: Expected max age %v, got %v", i, metric, mapping.bufCap, m.SummaryOptions.BufCap)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAction(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
testName string
|
||||
config string
|
||||
configBad bool
|
||||
expectedAction ActionType
|
||||
}{
|
||||
{
|
||||
// no action set
|
||||
testName: "no action set",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -1003,7 +1477,7 @@ mappings:
|
|||
expectedAction: ActionTypeMap,
|
||||
},
|
||||
{
|
||||
// map action set
|
||||
testName: "map action set",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -1014,7 +1488,7 @@ mappings:
|
|||
expectedAction: ActionTypeMap,
|
||||
},
|
||||
{
|
||||
// drop action set
|
||||
testName: "drop action set",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -1025,7 +1499,7 @@ mappings:
|
|||
expectedAction: ActionTypeDrop,
|
||||
},
|
||||
{
|
||||
// invalid action set
|
||||
testName: "invalid action set",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: test.*.*
|
||||
|
@ -1036,7 +1510,7 @@ mappings:
|
|||
expectedAction: ActionTypeDrop,
|
||||
},
|
||||
{
|
||||
// valid yaml example
|
||||
testName: "valid yaml example",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: "test\\.(\\w+)\\.(\\w+)\\.counter"
|
||||
|
@ -1049,7 +1523,7 @@ mappings:
|
|||
expectedAction: ActionTypeMap,
|
||||
},
|
||||
{
|
||||
// invalid yaml example
|
||||
testName: "invalid yaml example",
|
||||
config: `---
|
||||
mappings:
|
||||
- match: "test\.(\w+)\.(\w+)\.counter"
|
||||
|
@ -1063,6 +1537,10 @@ mappings:
|
|||
}
|
||||
|
||||
for i, scenario := range scenarios {
|
||||
if scenario.testName == "" {
|
||||
t.Fatalf("Missing testName in scenario %+v", scenario)
|
||||
}
|
||||
t.Run(scenario.testName, func(t *testing.T) {
|
||||
mapper := MetricMapper{}
|
||||
err := mapper.InitFromYAMLString(scenario.config, 0)
|
||||
if err != nil && !scenario.configBad {
|
||||
|
@ -1078,6 +1556,7 @@ mappings:
|
|||
t.Fatalf("%d: Expected action %v, got %v", i, scenario.expectedAction, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/statsd_exporter/pkg/clock"
|
||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
||||
"github.com/prometheus/statsd_exporter/pkg/metrics"
|
||||
|
@ -248,7 +249,7 @@ func (r *Registry) GetHistogram(metricName string, labels prometheus.Labels, hel
|
|||
var histogramVec *prometheus.HistogramVec
|
||||
if vh == nil {
|
||||
metricsCount.WithLabelValues("histogram").Inc()
|
||||
buckets := r.Mapper.Defaults.Buckets
|
||||
buckets := r.Mapper.Defaults.HistogramOptions.Buckets
|
||||
if mapping.HistogramOptions != nil && len(mapping.HistogramOptions.Buckets) > 0 {
|
||||
buckets = mapping.HistogramOptions.Buckets
|
||||
}
|
||||
|
@ -295,7 +296,7 @@ func (r *Registry) GetSummary(metricName string, labels prometheus.Labels, help
|
|||
var summaryVec *prometheus.SummaryVec
|
||||
if vh == nil {
|
||||
metricsCount.WithLabelValues("summary").Inc()
|
||||
quantiles := r.Mapper.Defaults.Quantiles
|
||||
quantiles := r.Mapper.Defaults.SummaryOptions.Quantiles
|
||||
if mapping != nil && mapping.SummaryOptions != nil && len(mapping.SummaryOptions.Quantiles) > 0 {
|
||||
quantiles = mapping.SummaryOptions.Quantiles
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue