mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2024-11-26 17:21:01 +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 (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
"github.com/prometheus/common/model"
|
|
||||||
|
|
||||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
||||||
)
|
)
|
||||||
|
@ -42,96 +39,82 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
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
|
func labelsNames(labels prometheus.Labels) []string {
|
||||||
// the label names and values in the provided labels map.
|
names := make([]string, 0, len(labels))
|
||||||
//
|
for labelName := range labels {
|
||||||
// Not safe for concurrent use! (Uses a shared buffer and hasher to save on
|
names = append(names, labelName)
|
||||||
// allocations.)
|
}
|
||||||
func hashNameAndLabels(name string, labels prometheus.Labels) uint64 {
|
sort.Strings(names)
|
||||||
hash.Reset()
|
return names
|
||||||
strBuf.Reset()
|
|
||||||
strBuf.WriteString(name)
|
|
||||||
hash.Write(strBuf.Bytes())
|
|
||||||
binary.BigEndian.PutUint64(intBuf, model.LabelsToSignature(labels))
|
|
||||||
hash.Write(intBuf)
|
|
||||||
return hash.Sum64()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CounterContainer struct {
|
type CounterContainer struct {
|
||||||
Elements map[uint64]prometheus.Counter
|
// metric name
|
||||||
|
Elements map[string]*prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCounterContainer() *CounterContainer {
|
func NewCounterContainer() *CounterContainer {
|
||||||
return &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) {
|
func (c *CounterContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Counter, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
counterVec, ok := c.Elements[metricName]
|
||||||
counter, ok := c.Elements[hash]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
counter = prometheus.NewCounter(prometheus.CounterOpts{
|
counterVec = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
Name: metricName,
|
Name: metricName,
|
||||||
Help: help,
|
Help: help,
|
||||||
ConstLabels: labels,
|
}, labelsNames(labels))
|
||||||
})
|
if err := prometheus.Register(counterVec); err != nil {
|
||||||
if err := prometheus.Register(counter); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.Elements[hash] = counter
|
c.Elements[metricName] = counterVec
|
||||||
}
|
}
|
||||||
return counter, nil
|
return counterVec.GetMetricWith(labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
type GaugeContainer struct {
|
type GaugeContainer struct {
|
||||||
Elements map[uint64]prometheus.Gauge
|
Elements map[string]*prometheus.GaugeVec
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGaugeContainer() *GaugeContainer {
|
func NewGaugeContainer() *GaugeContainer {
|
||||||
return &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) {
|
func (c *GaugeContainer) Get(metricName string, labels prometheus.Labels, help string) (prometheus.Gauge, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
gaugeVec, ok := c.Elements[metricName]
|
||||||
gauge, ok := c.Elements[hash]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
gauge = prometheus.NewGauge(prometheus.GaugeOpts{
|
gaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Name: metricName,
|
Name: metricName,
|
||||||
Help: help,
|
Help: help,
|
||||||
ConstLabels: labels,
|
}, labelsNames(labels))
|
||||||
})
|
if err := prometheus.Register(gaugeVec); err != nil {
|
||||||
if err := prometheus.Register(gauge); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.Elements[hash] = gauge
|
c.Elements[metricName] = gaugeVec
|
||||||
}
|
}
|
||||||
return gauge, nil
|
return gaugeVec.GetMetricWith(labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SummaryContainer struct {
|
type SummaryContainer struct {
|
||||||
Elements map[uint64]prometheus.Summary
|
Elements map[string]*prometheus.SummaryVec
|
||||||
mapper *mapper.MetricMapper
|
mapper *mapper.MetricMapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSummaryContainer(mapper *mapper.MetricMapper) *SummaryContainer {
|
func NewSummaryContainer(mapper *mapper.MetricMapper) *SummaryContainer {
|
||||||
return &SummaryContainer{
|
return &SummaryContainer{
|
||||||
Elements: make(map[uint64]prometheus.Summary),
|
Elements: make(map[string]*prometheus.SummaryVec),
|
||||||
mapper: mapper,
|
mapper: mapper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Summary, error) {
|
func (c *SummaryContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Summary, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
summaryVec, ok := c.Elements[metricName]
|
||||||
summary, ok := c.Elements[hash]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
quantiles := c.mapper.Defaults.Quantiles
|
quantiles := c.mapper.Defaults.Quantiles
|
||||||
if mapping != nil && mapping.Quantiles != nil && len(mapping.Quantiles) > 0 {
|
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 {
|
for _, q := range quantiles {
|
||||||
objectives[q.Quantile] = q.Error
|
objectives[q.Quantile] = q.Error
|
||||||
}
|
}
|
||||||
summary = prometheus.NewSummary(
|
summaryVec = prometheus.NewSummaryVec(
|
||||||
prometheus.SummaryOpts{
|
prometheus.SummaryOpts{
|
||||||
Name: metricName,
|
Name: metricName,
|
||||||
Help: help,
|
Help: help,
|
||||||
ConstLabels: labels,
|
Objectives: objectives,
|
||||||
Objectives: objectives,
|
}, labelsNames(labels))
|
||||||
})
|
if err := prometheus.Register(summaryVec); err != nil {
|
||||||
if err := prometheus.Register(summary); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.Elements[hash] = summary
|
c.Elements[metricName] = summaryVec
|
||||||
}
|
}
|
||||||
return summary, nil
|
return summaryVec.GetMetricWith(labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HistogramContainer struct {
|
type HistogramContainer struct {
|
||||||
Elements map[uint64]prometheus.Histogram
|
Elements map[string]*prometheus.HistogramVec
|
||||||
mapper *mapper.MetricMapper
|
mapper *mapper.MetricMapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHistogramContainer(mapper *mapper.MetricMapper) *HistogramContainer {
|
func NewHistogramContainer(mapper *mapper.MetricMapper) *HistogramContainer {
|
||||||
return &HistogramContainer{
|
return &HistogramContainer{
|
||||||
Elements: make(map[uint64]prometheus.Histogram),
|
Elements: make(map[string]*prometheus.HistogramVec),
|
||||||
mapper: mapper,
|
mapper: mapper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Histogram, error) {
|
func (c *HistogramContainer) Get(metricName string, labels prometheus.Labels, help string, mapping *mapper.MetricMapping) (prometheus.Histogram, error) {
|
||||||
hash := hashNameAndLabels(metricName, labels)
|
histogramVec, ok := c.Elements[metricName]
|
||||||
histogram, ok := c.Elements[hash]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
buckets := c.mapper.Defaults.Buckets
|
buckets := c.mapper.Defaults.Buckets
|
||||||
if mapping != nil && mapping.Buckets != nil && len(mapping.Buckets) > 0 {
|
if mapping != nil && mapping.Buckets != nil && len(mapping.Buckets) > 0 {
|
||||||
buckets = mapping.Buckets
|
buckets = mapping.Buckets
|
||||||
}
|
}
|
||||||
histogram = prometheus.NewHistogram(
|
histogramVec := prometheus.NewHistogramVec(
|
||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Name: metricName,
|
Name: metricName,
|
||||||
Help: help,
|
Help: help,
|
||||||
ConstLabels: labels,
|
Buckets: buckets,
|
||||||
Buckets: buckets,
|
}, labelsNames(labels))
|
||||||
})
|
if err := prometheus.Register(histogramVec); err != nil {
|
||||||
c.Elements[hash] = histogram
|
|
||||||
if err := prometheus.Register(histogram); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.Elements[metricName] = histogramVec
|
||||||
}
|
}
|
||||||
return histogram, nil
|
return histogramVec.GetMetricWith(labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event interface {
|
type Event interface {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/prometheus/statsd_exporter/pkg/mapper"
|
"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) {
|
func TestHistogramUnits(t *testing.T) {
|
||||||
events := make(chan Events, 1)
|
events := make(chan Events, 1)
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
@ -106,14 +97,23 @@ func TestHistogramUnits(t *testing.T) {
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
close(events)
|
close(events)
|
||||||
}()
|
}()
|
||||||
mock := &MockHistogram{}
|
|
||||||
key := hashNameAndLabels(name, nil)
|
|
||||||
ex.Histograms.Elements[key] = mock
|
|
||||||
ex.Listen(events)
|
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")
|
t.Fatalf("Histogram observations not scaled into Seconds")
|
||||||
} else if mock.value != .300 {
|
} else if value != .300 {
|
||||||
t.Fatalf("Received unexpected value for histogram observation %f != .300", mock.value)
|
t.Fatalf("Received unexpected value for histogram observation %f != .300", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue