mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2025-02-16 23:55:15 +00:00
feat: configurable quantiles for Summaries
* Quantile values for a Summary are now configurable. * The default quantiles (DefObjectives) in the prometheus Go client library is deprecated. This commit removes the reliance on it. Signed-off-by: Harry Bagdi <harrybagdi@gmail.com>
This commit is contained in:
parent
0ffa3f9865
commit
a144b1f9f7
4 changed files with 91 additions and 6 deletions
|
@ -176,6 +176,15 @@ mappings:
|
||||||
provider: "$2"
|
provider: "$2"
|
||||||
outcome: "$3"
|
outcome: "$3"
|
||||||
job: "${1}_server"
|
job: "${1}_server"
|
||||||
|
quantiles: # Optionally configure quantiles for your summaries
|
||||||
|
- quantile: 0.99 # https://prometheus.io/docs/practices/histograms/#quantiles
|
||||||
|
error: 0.001
|
||||||
|
- quantile: 0.95
|
||||||
|
error: 0.01
|
||||||
|
- quantile: 0.9
|
||||||
|
error: 0.05
|
||||||
|
- quantile: 0.5
|
||||||
|
error: 0.005
|
||||||
```
|
```
|
||||||
|
|
||||||
Another capability when using YAML configuration is the ability to define matches
|
Another capability when using YAML configuration is the ability to define matches
|
||||||
|
|
18
exporter.go
18
exporter.go
|
@ -117,23 +117,34 @@ func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels, help s
|
||||||
|
|
||||||
type SummaryContainer struct {
|
type SummaryContainer struct {
|
||||||
Elements map[uint64]prometheus.Summary
|
Elements map[uint64]prometheus.Summary
|
||||||
|
mapper *metricMapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSummaryContainer() *SummaryContainer {
|
func NewSummaryContainer(mapper *metricMapper) *SummaryContainer {
|
||||||
return &SummaryContainer{
|
return &SummaryContainer{
|
||||||
Elements: make(map[uint64]prometheus.Summary),
|
Elements: make(map[uint64]prometheus.Summary),
|
||||||
|
mapper: mapper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Summary, error) {
|
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *metricMapping) (prometheus.Summary, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
hash := hashNameAndLabels(metricName, labels)
|
||||||
summary, ok := c.Elements[hash]
|
summary, ok := c.Elements[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
quantiles := c.mapper.Defaults.Quantiles
|
||||||
|
if mapping != nil && mapping.Quantiles != nil && len(mapping.Quantiles) > 0 {
|
||||||
|
quantiles = mapping.Quantiles
|
||||||
|
}
|
||||||
|
objectives := make(map[float64]float64)
|
||||||
|
for _, q := range quantiles {
|
||||||
|
objectives[q.Quantile] = q.Error
|
||||||
|
}
|
||||||
summary = prometheus.NewSummary(
|
summary = prometheus.NewSummary(
|
||||||
prometheus.SummaryOpts{
|
prometheus.SummaryOpts{
|
||||||
Name: metricName,
|
Name: metricName,
|
||||||
Help: help,
|
Help: help,
|
||||||
ConstLabels: labels,
|
ConstLabels: labels,
|
||||||
|
Objectives: objectives,
|
||||||
})
|
})
|
||||||
if err := prometheus.Register(summary); err != nil {
|
if err := prometheus.Register(summary); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -350,6 +361,7 @@ func (b *Exporter) Listen(e <-chan Events) {
|
||||||
metricName,
|
metricName,
|
||||||
prometheusLabels,
|
prometheusLabels,
|
||||||
help,
|
help,
|
||||||
|
mapping,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
summary.Observe(event.Value())
|
summary.Observe(event.Value())
|
||||||
|
@ -375,7 +387,7 @@ func NewExporter(mapper *metricMapper) *Exporter {
|
||||||
return &Exporter{
|
return &Exporter{
|
||||||
Counters: NewCounterContainer(),
|
Counters: NewCounterContainer(),
|
||||||
Gauges: NewGaugeContainer(),
|
Gauges: NewGaugeContainer(),
|
||||||
Summaries: NewSummaryContainer(),
|
Summaries: NewSummaryContainer(mapper),
|
||||||
Histograms: NewHistogramContainer(mapper),
|
Histograms: NewHistogramContainer(mapper),
|
||||||
mapper: mapper,
|
mapper: mapper,
|
||||||
}
|
}
|
||||||
|
|
27
mapper.go
27
mapper.go
|
@ -34,9 +34,10 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type mapperConfigDefaults struct {
|
type mapperConfigDefaults struct {
|
||||||
TimerType timerType `yaml:"timer_type"`
|
TimerType timerType `yaml:"timer_type"`
|
||||||
Buckets []float64 `yaml:"buckets"`
|
Buckets []float64 `yaml:"buckets"`
|
||||||
MatchType matchType `yaml:"match_type"`
|
Quantiles []metricObjective `yaml:"quantiles"`
|
||||||
|
MatchType matchType `yaml:"match_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type metricMapper struct {
|
type metricMapper struct {
|
||||||
|
@ -54,12 +55,24 @@ type metricMapping struct {
|
||||||
Labels prometheus.Labels `yaml:"labels"`
|
Labels prometheus.Labels `yaml:"labels"`
|
||||||
TimerType timerType `yaml:"timer_type"`
|
TimerType timerType `yaml:"timer_type"`
|
||||||
Buckets []float64 `yaml:"buckets"`
|
Buckets []float64 `yaml:"buckets"`
|
||||||
|
Quantiles []metricObjective `yaml:"quantiles"`
|
||||||
MatchType matchType `yaml:"match_type"`
|
MatchType matchType `yaml:"match_type"`
|
||||||
HelpText string `yaml:"help"`
|
HelpText string `yaml:"help"`
|
||||||
Action actionType `yaml:"action"`
|
Action actionType `yaml:"action"`
|
||||||
MatchMetricType metricType `yaml:"match_metric_type"`
|
MatchMetricType metricType `yaml:"match_metric_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type metricObjective struct {
|
||||||
|
Quantile float64 `yaml:"quantile"`
|
||||||
|
Error float64 `yaml:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultQuantiles = []metricObjective{
|
||||||
|
{Quantile: 0.5, Error: 0.05},
|
||||||
|
{Quantile: 0.9, Error: 0.01},
|
||||||
|
{Quantile: 0.99, Error: 0.001},
|
||||||
|
}
|
||||||
|
|
||||||
func (m *metricMapper) initFromYAMLString(fileContents string) error {
|
func (m *metricMapper) initFromYAMLString(fileContents string) error {
|
||||||
var n metricMapper
|
var n metricMapper
|
||||||
|
|
||||||
|
@ -71,6 +84,10 @@ func (m *metricMapper) initFromYAMLString(fileContents string) error {
|
||||||
n.Defaults.Buckets = prometheus.DefBuckets
|
n.Defaults.Buckets = prometheus.DefBuckets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.Defaults.Quantiles == nil || len(n.Defaults.Quantiles) == 0 {
|
||||||
|
n.Defaults.Quantiles = defaultQuantiles
|
||||||
|
}
|
||||||
|
|
||||||
if n.Defaults.MatchType == matchTypeDefault {
|
if n.Defaults.MatchType == matchTypeDefault {
|
||||||
n.Defaults.MatchType = matchTypeGlob
|
n.Defaults.MatchType = matchTypeGlob
|
||||||
}
|
}
|
||||||
|
@ -130,6 +147,10 @@ func (m *metricMapper) initFromYAMLString(fileContents string) error {
|
||||||
currentMapping.Buckets = n.Defaults.Buckets
|
currentMapping.Buckets = n.Defaults.Buckets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if currentMapping.Quantiles == nil || len(currentMapping.Quantiles) == 0 {
|
||||||
|
currentMapping.Quantiles = n.Defaults.Quantiles
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
type mappings map[string]struct {
|
type mappings map[string]struct {
|
||||||
name string
|
name string
|
||||||
labels map[string]string
|
labels map[string]string
|
||||||
|
quantiles []metricObjective
|
||||||
notPresent bool
|
notPresent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,11 +288,40 @@ mappings:
|
||||||
timer_type: summary
|
timer_type: summary
|
||||||
name: "foo"
|
name: "foo"
|
||||||
labels: {}
|
labels: {}
|
||||||
|
quantiles:
|
||||||
|
- quantile: 0.42
|
||||||
|
error: 0.04
|
||||||
|
- quantile: 0.7
|
||||||
|
error: 0.002
|
||||||
`,
|
`,
|
||||||
mappings: mappings{
|
mappings: mappings{
|
||||||
"test.*.*": {
|
"test.*.*": {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
labels: map[string]string{},
|
labels: map[string]string{},
|
||||||
|
quantiles: []metricObjective{
|
||||||
|
{Quantile: 0.42, Error: 0.04},
|
||||||
|
{Quantile: 0.7, Error: 0.002},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: `---
|
||||||
|
mappings:
|
||||||
|
- match: test1.*.*
|
||||||
|
timer_type: summary
|
||||||
|
name: "foo"
|
||||||
|
labels: {}
|
||||||
|
`,
|
||||||
|
mappings: mappings{
|
||||||
|
"test1.*.*": {
|
||||||
|
name: "foo",
|
||||||
|
labels: map[string]string{},
|
||||||
|
quantiles: []metricObjective{
|
||||||
|
{Quantile: 0.5, Error: 0.05},
|
||||||
|
{Quantile: 0.9, Error: 0.01},
|
||||||
|
{Quantile: 0.99, Error: 0.001},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -471,6 +501,19 @@ 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))
|
||||||
|
}
|
||||||
|
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.Error != m.Quantiles[i].Error {
|
||||||
|
t.Fatalf("%d.%q: Expected Error margin %v, got %v", i, metric, m.Quantiles[i].Error, quantile.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue