add support for deltas in histogram and summaries

This commit is contained in:
bergquist 2017-09-06 19:23:03 +02:00 committed by Carl Bergquist
parent 2de94d6548
commit fca80ff525
4 changed files with 60 additions and 22 deletions

View File

@ -13,7 +13,7 @@
// Package graphite provides a bridge to push Prometheus metrics to a Graphite
// server.
package graphitepublisher
package graphitebridge
import (
"bufio"
@ -275,14 +275,40 @@ func writeMetric(buf *bufio.Writer, m model.Metric, mf *dto.MetricFamily) error
}
}
if mf.GetType() == dto.MetricType_COUNTER {
// Adding the `.count` suffix makes it possible to configure
// `sum` as rollup strategy for counters
if err = addExtentionConventionForRollups(buf, mf, m); err != nil {
return err
}
return nil
}
func addExtentionConventionForRollups(buf *bufio.Writer, mf *dto.MetricFamily, m model.Metric) error {
// Adding `.count` `.sum` suffix makes it possible to configure
// different rollup strategies based on metric type
mfType := mf.GetType()
var err error
if mfType == dto.MetricType_COUNTER {
if _, err = fmt.Fprint(buf, ".count"); err != nil {
return err
}
}
if mfType == dto.MetricType_SUMMARY || mfType == dto.MetricType_HISTOGRAM {
if strings.HasSuffix(string(m[model.MetricNameLabel]), "_count") {
if _, err = fmt.Fprint(buf, ".count"); err != nil {
return err
}
}
}
if mfType == dto.MetricType_HISTOGRAM {
if strings.HasSuffix(string(m[model.MetricNameLabel]), "_sum") {
if _, err = fmt.Fprint(buf, ".sum"); err != nil {
return err
}
}
}
return nil
}
@ -318,19 +344,31 @@ func replaceInvalidRune(c rune) rune {
}
func (b *Bridge) replaceCounterWithDelta(mf *dto.MetricFamily, metric model.Metric, value model.SampleValue) float64 {
if mf.GetType() != dto.MetricType_COUNTER {
return float64(value)
}
if !b.countersAsDetlas {
return float64(value)
}
mfType := mf.GetType()
if mfType == dto.MetricType_COUNTER {
return b.returnDelta(metric, value)
}
if mfType == dto.MetricType_SUMMARY {
if strings.HasSuffix(string(metric[model.MetricNameLabel]), "_count") {
return b.returnDelta(metric, value)
}
}
return float64(value)
//println("use delta for", metric[model.MetricNameLabel], mf.GetType().String())
//TODO(bergquist): turn _count in summery into delta
//TODO(bergquist): turn _count in histogram into delta
}
func (b *Bridge) returnDelta(metric model.Metric, value model.SampleValue) float64 {
key := metric.Fingerprint()
_, exists := b.lastValue[key]
if !exists {

View File

@ -1,4 +1,4 @@
package graphitepublisher
package graphitebridge
import (
"bufio"
@ -142,12 +142,12 @@ func TestWriteSummary(t *testing.T) {
prefix.name.constname.constvalue.labelname.val1.quantile.0_9 30 1477043
prefix.name.constname.constvalue.labelname.val1.quantile.0_99 30 1477043
prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
prefix.name_count.constname.constvalue.labelname.val1 3 1477043
prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
prefix.name.constname.constvalue.labelname.val2.quantile.0_5 30 1477043
prefix.name.constname.constvalue.labelname.val2.quantile.0_9 40 1477043
prefix.name.constname.constvalue.labelname.val2.quantile.0_99 40 1477043
prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
prefix.name_count.constname.constvalue.labelname.val2 3 1477043
prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
`
if got := buf.String(); want != got {
@ -201,15 +201,15 @@ func TestWriteHistogram(t *testing.T) {
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_02 0 1477043
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_05 0 1477043
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_1 0 1477043
prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
prefix.name_count.constname.constvalue.labelname.val1 3 1477043
prefix.name_sum.constname.constvalue.labelname.val1.sum 60 1477043
prefix.name_count.constname.constvalue.labelname.val1.count 3 1477043
prefix.name_bucket.constname.constvalue.labelname.val1.le._Inf 3 1477043
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_01 0 1477043
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_02 0 1477043
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_05 0 1477043
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_1 0 1477043
prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
prefix.name_count.constname.constvalue.labelname.val2 3 1477043
prefix.name_sum.constname.constvalue.labelname.val2.sum 90 1477043
prefix.name_count.constname.constvalue.labelname.val2.count 3 1477043
prefix.name_bucket.constname.constvalue.labelname.val2.le._Inf 3 1477043
`
if got := buf.String(); want != got {

View File

@ -4,7 +4,7 @@ import (
"context"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/metrics/graphitepublisher"
"github.com/grafana/grafana/pkg/metrics/graphitebridge"
)
var metricsLogger log.Logger = log.New("metrics")
@ -22,7 +22,7 @@ func Init(settings *MetricSettings) {
initMetricVars(settings)
if settings.GraphiteBridgeConfig != nil {
bridge, err := graphitepublisher.NewBridge(settings.GraphiteBridgeConfig)
bridge, err := graphitebridge.NewBridge(settings.GraphiteBridgeConfig)
if err != nil {
metricsLogger.Error("failed to create graphite bridge", "error", err)
} else {

View File

@ -4,7 +4,7 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/metrics/graphitepublisher"
"github.com/grafana/grafana/pkg/metrics/graphitebridge"
"github.com/grafana/grafana/pkg/setting"
"github.com/prometheus/client_golang/prometheus"
ini "gopkg.in/ini.v1"
@ -13,7 +13,7 @@ import (
type MetricSettings struct {
Enabled bool
IntervalSeconds int64
GraphiteBridgeConfig *graphitepublisher.Config
GraphiteBridgeConfig *graphitebridge.Config
}
func ReadSettings(file *ini.File) *MetricSettings {
@ -45,7 +45,7 @@ func ReadSettings(file *ini.File) *MetricSettings {
return settings
}
func parseGraphiteSettings(settings *MetricSettings, file *ini.File) (*graphitepublisher.Config, error) {
func parseGraphiteSettings(settings *MetricSettings, file *ini.File) (*graphitebridge.Config, error) {
graphiteSection, err := setting.Cfg.GetSection("metrics.graphite")
if err != nil {
return nil, nil
@ -56,7 +56,7 @@ func parseGraphiteSettings(settings *MetricSettings, file *ini.File) (*graphitep
return nil, nil
}
cfg := &graphitepublisher.Config{
cfg := &graphitebridge.Config{
URL: address,
Prefix: graphiteSection.Key("prefix").MustString("prod.grafana.%(instance_name)s"),
CountersAsDelta: true,
@ -64,7 +64,7 @@ func parseGraphiteSettings(settings *MetricSettings, file *ini.File) (*graphitep
Interval: time.Duration(settings.IntervalSeconds) * time.Second,
Timeout: 10 * time.Second,
Logger: &logWrapper{logger: metricsLogger},
ErrorHandling: graphitepublisher.ContinueOnError,
ErrorHandling: graphitebridge.ContinueOnError,
}
safeInstanceName := strings.Replace(setting.InstanceName, ".", "_", -1)