mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2024-11-22 15:30:59 +00:00
Replace Metrics with Collectors
- use MetricVec family instead of Metric - dynamic label values instead of ConstLabels - use dto.Metric to gain histrogram value in exporter_test - remove hash calculations Signed-off-by: Ivan Mikheykin <ivan.mikheykin@flant.com>
This commit is contained in:
parent
ef5d2c8a79
commit
b638b9d808
2 changed files with 67 additions and 87 deletions
122
exporter.go
122
exporter.go
|
@ -15,20 +15,17 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/log"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
||||
)
|
||||
|
@ -42,96 +39,82 @@ const (
|
|||
|
||||
var (
|
||||
illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||
|
||||
hash = fnv.New64a()
|
||||
strBuf bytes.Buffer // Used for hashing.
|
||||
intBuf = make([]byte, 8)
|
||||
)
|
||||
|
||||
// hashNameAndLabels returns a hash value of the provided name string and all
|
||||
// the label names and values in the provided labels map.
|
||||
//
|
||||
// Not safe for concurrent use! (Uses a shared buffer and hasher to save on
|
||||
// allocations.)
|
||||
func hashNameAndLabels(name string, labels prometheus.Labels) uint64 {
|
||||
hash.Reset()
|
||||
strBuf.Reset()
|
||||
strBuf.WriteString(name)
|
||||
hash.Write(strBuf.Bytes())
|
||||
binary.BigEndian.PutUint64(intBuf, model.LabelsToSignature(labels))
|
||||
hash.Write(intBuf)
|
||||
return hash.Sum64()
|
||||
func labelsNames(labels prometheus.Labels) []string {
|
||||
names := make([]string, 0, len(labels))
|
||||
for labelName := range labels {
|
||||
names = append(names, labelName)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
type CounterContainer struct {
|
||||
Elements map[uint64]prometheus.Counter
|
||||
// metric name
|
||||
Elements map[string]*prometheus.CounterVec
|
||||
}
|
||||
|
||||
func NewCounterContainer() *CounterContainer {
|
||||
return &CounterContainer{
|
||||
Elements: make(map[uint64]prometheus.Counter),
|
||||
Elements: make(map[string]*prometheus.CounterVec),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CounterContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Counter, error) {
|
||||
hash := hashNameAndLabels(metricName, labels)
|
||||
counter, ok := c.Elements[hash]
|
||||
counterVec, ok := c.Elements[metricName]
|
||||
if !ok {
|
||||
counter = prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
ConstLabels: labels,
|
||||
})
|
||||
if err := prometheus.Register(counter); err != nil {
|
||||
counterVec = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
}, labelsNames(labels))
|
||||
if err := prometheus.Register(counterVec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Elements[hash] = counter
|
||||
c.Elements[metricName] = counterVec
|
||||
}
|
||||
return counter, nil
|
||||
return counterVec.GetMetricWith(labels)
|
||||
}
|
||||
|
||||
type GaugeContainer struct {
|
||||
Elements map[uint64]prometheus.Gauge
|
||||
Elements map[string]*prometheus.GaugeVec
|
||||
}
|
||||
|
||||
func NewGaugeContainer() *GaugeContainer {
|
||||
return &GaugeContainer{
|
||||
Elements: make(map[uint64]prometheus.Gauge),
|
||||
Elements: make(map[string]*prometheus.GaugeVec),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Gauge, error) {
|
||||
hash := hashNameAndLabels(metricName, labels)
|
||||
gauge, ok := c.Elements[hash]
|
||||
gaugeVec, ok := c.Elements[metricName]
|
||||
if !ok {
|
||||
gauge = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
ConstLabels: labels,
|
||||
})
|
||||
if err := prometheus.Register(gauge); err != nil {
|
||||
gaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
}, labelsNames(labels))
|
||||
if err := prometheus.Register(gaugeVec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Elements[hash] = gauge
|
||||
c.Elements[metricName] = gaugeVec
|
||||
}
|
||||
return gauge, nil
|
||||
return gaugeVec.GetMetricWith(labels)
|
||||
}
|
||||
|
||||
type SummaryContainer struct {
|
||||
Elements map[uint64]prometheus.Summary
|
||||
Elements map[string]*prometheus.SummaryVec
|
||||
mapper *mapper.MetricMapper
|
||||
}
|
||||
|
||||
func NewSummaryContainer(mapper *mapper.MetricMapper) *SummaryContainer {
|
||||
return &SummaryContainer{
|
||||
Elements: make(map[uint64]prometheus.Summary),
|
||||
Elements: make(map[string]*prometheus.SummaryVec),
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Summary, error) {
|
||||
hash := hashNameAndLabels(metricName, labels)
|
||||
summary, ok := c.Elements[hash]
|
||||
summaryVec, ok := c.Elements[metricName]
|
||||
if !ok {
|
||||
quantiles := c.mapper.Defaults.Quantiles
|
||||
if mapping != nil && mapping.Quantiles != nil && len(mapping.Quantiles) > 0 {
|
||||
|
@ -141,54 +124,51 @@ func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help
|
|||
for _, q := range quantiles {
|
||||
objectives[q.Quantile] = q.Error
|
||||
}
|
||||
summary = prometheus.NewSummary(
|
||||
summaryVec = prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
ConstLabels: labels,
|
||||
Objectives: objectives,
|
||||
})
|
||||
if err := prometheus.Register(summary); err != nil {
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
Objectives: objectives,
|
||||
}, labelsNames(labels))
|
||||
if err := prometheus.Register(summaryVec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Elements[hash] = summary
|
||||
c.Elements[metricName] = summaryVec
|
||||
}
|
||||
return summary, nil
|
||||
return summaryVec.GetMetricWith(labels)
|
||||
}
|
||||
|
||||
type HistogramContainer struct {
|
||||
Elements map[uint64]prometheus.Histogram
|
||||
Elements map[string]*prometheus.HistogramVec
|
||||
mapper *mapper.MetricMapper
|
||||
}
|
||||
|
||||
func NewHistogramContainer(mapper *mapper.MetricMapper) *HistogramContainer {
|
||||
return &HistogramContainer{
|
||||
Elements: make(map[uint64]prometheus.Histogram),
|
||||
Elements: make(map[string]*prometheus.HistogramVec),
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Histogram, error) {
|
||||
hash := hashNameAndLabels(metricName, labels)
|
||||
histogram, ok := c.Elements[hash]
|
||||
histogramVec, ok := c.Elements[metricName]
|
||||
if !ok {
|
||||
buckets := c.mapper.Defaults.Buckets
|
||||
if mapping != nil && mapping.Buckets != nil && len(mapping.Buckets) > 0 {
|
||||
buckets = mapping.Buckets
|
||||
}
|
||||
histogram = prometheus.NewHistogram(
|
||||
histogramVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
ConstLabels: labels,
|
||||
Buckets: buckets,
|
||||
})
|
||||
c.Elements[hash] = histogram
|
||||
if err := prometheus.Register(histogram); err != nil {
|
||||
Name: metricName,
|
||||
Help: help,
|
||||
Buckets: buckets,
|
||||
}, labelsNames(labels))
|
||||
if err := prometheus.Register(histogramVec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Elements[metricName] = histogramVec
|
||||
}
|
||||
return histogram, nil
|
||||
return histogramVec.GetMetricWith(labels)
|
||||
}
|
||||
|
||||
type Event interface {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
||||
)
|
||||
|
@ -78,16 +79,6 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type MockHistogram struct {
|
||||
prometheus.Metric
|
||||
prometheus.Collector
|
||||
value float64
|
||||
}
|
||||
|
||||
func (h *MockHistogram) Observe(n float64) {
|
||||
h.value = n
|
||||
}
|
||||
|
||||
func TestHistogramUnits(t *testing.T) {
|
||||
events := make(chan Events, 1)
|
||||
name := "foo"
|
||||
|
@ -106,14 +97,23 @@ func TestHistogramUnits(t *testing.T) {
|
|||
time.Sleep(time.Millisecond * 100)
|
||||
close(events)
|
||||
}()
|
||||
mock := &MockHistogram{}
|
||||
key := hashNameAndLabels(name, nil)
|
||||
ex.Histograms.Elements[key] = mock
|
||||
|
||||
ex.Listen(events)
|
||||
if mock.value == 300 {
|
||||
|
||||
histogram, err := ex.Histograms.Get(name, prometheus.Labels{}, "", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Histogram not registered")
|
||||
}
|
||||
|
||||
// check the state of the histogram by
|
||||
// (ab)using its Write method (which is usually only used by Prometheus internally).
|
||||
metric := &dto.Metric{}
|
||||
histogram.Write(metric)
|
||||
value := *metric.Histogram.SampleSum
|
||||
if value == 300 {
|
||||
t.Fatalf("Histogram observations not scaled into Seconds")
|
||||
} else if mock.value != .300 {
|
||||
t.Fatalf("Received unexpected value for histogram observation %f != .300", mock.value)
|
||||
} else if value != .300 {
|
||||
t.Fatalf("Received unexpected value for histogram observation %f != .300", value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue