Skip to content

Commit

Permalink
Merge pull request #151 from hashicorp/biazmoreira/addgaugefloat64
Browse files Browse the repository at this point in the history
Add GaugeFloat64 API
  • Loading branch information
biazmoreira authored May 19, 2023
2 parents 8cabd9e + eb30b88 commit 8586014
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 33 deletions.
10 changes: 5 additions & 5 deletions circonus/circonus.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ type Config cgm.Config
// NewCirconusSink - create new metric sink for circonus
//
// one of the following must be supplied:
// - API Token - search for an existing check or create a new check
// - API Token + Check Id - the check identified by check id will be used
// - API Token + Check Submission URL - the check identified by the submission url will be used
// - Check Submission URL - the check identified by the submission url will be used
// metric management will be *disabled*
// - API Token - search for an existing check or create a new check
// - API Token + Check Id - the check identified by check id will be used
// - API Token + Check Submission URL - the check identified by the submission url will be used
// - Check Submission URL - the check identified by the submission url will be used
// metric management will be *disabled*
//
// Note: If submission url is supplied w/o an api token, the public circonus ca cert will be used
// to verify the broker for metrics submission.
Expand Down
12 changes: 12 additions & 0 deletions datadog/dogstatsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (s *DogStatsdSink) SetGauge(key []string, val float32) {
s.SetGaugeWithLabels(key, val, nil)
}

func (s *DogStatsdSink) SetPrecisionGauge(key []string, val float64) {
s.SetPrecisionGaugeWithLabels(key, val, nil)
}

func (s *DogStatsdSink) IncrCounter(key []string, val float32) {
s.IncrCounterWithLabels(key, val, nil)
}
Expand All @@ -108,6 +112,14 @@ func (s *DogStatsdSink) SetGaugeWithLabels(key []string, val float32, labels []m
s.client.Gauge(flatKey, float64(val), tags, rate)
}

// The following ...WithLabels methods correspond to Datadog's Tag extension to Statsd.
// http://docs.datadoghq.com/guides/dogstatsd/#tags
func (s *DogStatsdSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []metrics.Label) {
flatKey, tags := s.getFlatkeyAndCombinedLabels(key, labels)
rate := 1.0
s.client.Gauge(flatKey, val, tags, rate)
}

func (s *DogStatsdSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) {
flatKey, tags := s.getFlatkeyAndCombinedLabels(key, labels)
rate := 1.0
Expand Down
33 changes: 27 additions & 6 deletions inmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type IntervalMetrics struct {
// Gauges maps the key to the last set value
Gauges map[string]GaugeValue

// PrecisionGauges maps the key to the last set value
PrecisionGauges map[string]PrecisionGaugeValue

// Points maps the string to the list of emitted values
// from EmitKey
Points map[string][]float32
Expand All @@ -64,12 +67,13 @@ type IntervalMetrics struct {
// NewIntervalMetrics creates a new IntervalMetrics for a given interval
func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
return &IntervalMetrics{
Interval: intv,
Gauges: make(map[string]GaugeValue),
Points: make(map[string][]float32),
Counters: make(map[string]SampledValue),
Samples: make(map[string]SampledValue),
done: make(chan struct{}),
Interval: intv,
Gauges: make(map[string]GaugeValue),
PrecisionGauges: make(map[string]PrecisionGaugeValue),
Points: make(map[string][]float32),
Counters: make(map[string]SampledValue),
Samples: make(map[string]SampledValue),
done: make(chan struct{}),
}
}

Expand Down Expand Up @@ -174,6 +178,19 @@ func (i *InmemSink) SetGaugeWithLabels(key []string, val float32, labels []Label
intv.Gauges[k] = GaugeValue{Name: name, Value: val, Labels: labels}
}

func (i *InmemSink) SetPrecisionGauge(key []string, val float64) {
i.SetPrecisionGaugeWithLabels(key, val, nil)
}

func (i *InmemSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
k, name := i.flattenKeyLabels(key, labels)
intv := i.getInterval()

intv.Lock()
defer intv.Unlock()
intv.PrecisionGauges[k] = PrecisionGaugeValue{Name: name, Value: val, Labels: labels}
}

func (i *InmemSink) EmitKey(key []string, val float32) {
k := i.flattenKey(key)
intv := i.getInterval()
Expand Down Expand Up @@ -257,6 +274,10 @@ func (i *InmemSink) Data() []*IntervalMetrics {
for k, v := range current.Gauges {
copyCurrent.Gauges[k] = v
}
copyCurrent.PrecisionGauges = make(map[string]PrecisionGaugeValue, len(current.PrecisionGauges))
for k, v := range current.PrecisionGauges {
copyCurrent.PrecisionGauges[k] = v
}
// saved values will be not change, just copy its link
copyCurrent.Points = make(map[string][]float32, len(current.Points))
for k, v := range current.Points {
Expand Down
41 changes: 33 additions & 8 deletions inmem_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import (

// MetricsSummary holds a roll-up of metrics info for a given interval
type MetricsSummary struct {
Timestamp string
Gauges []GaugeValue
Points []PointValue
Counters []SampledValue
Samples []SampledValue
Timestamp string
Gauges []GaugeValue
PrecisionGauges []PrecisionGaugeValue
Points []PointValue
Counters []SampledValue
Samples []SampledValue
}

type GaugeValue struct {
Expand All @@ -26,6 +27,15 @@ type GaugeValue struct {
DisplayLabels map[string]string `json:"Labels"`
}

type PrecisionGaugeValue struct {
Name string
Hash string `json:"-"`
Value float64

Labels []Label `json:"-"`
DisplayLabels map[string]string `json:"Labels"`
}

type PointValue struct {
Name string
Points []float32
Expand Down Expand Up @@ -77,9 +87,10 @@ func newMetricSummaryFromInterval(interval *IntervalMetrics) MetricsSummary {
defer interval.RUnlock()

summary := MetricsSummary{
Timestamp: interval.Interval.Round(time.Second).UTC().String(),
Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
Points: make([]PointValue, 0, len(interval.Points)),
Timestamp: interval.Interval.Round(time.Second).UTC().String(),
Gauges: make([]GaugeValue, 0, len(interval.Gauges)),
PrecisionGauges: make([]PrecisionGaugeValue, 0, len(interval.PrecisionGauges)),
Points: make([]PointValue, 0, len(interval.Points)),
}

// Format and sort the output of each metric type, so it gets displayed in a
Expand All @@ -105,6 +116,20 @@ func newMetricSummaryFromInterval(interval *IntervalMetrics) MetricsSummary {
return summary.Gauges[i].Hash < summary.Gauges[j].Hash
})

for hash, value := range interval.PrecisionGauges {
value.Hash = hash
value.DisplayLabels = make(map[string]string)
for _, label := range value.Labels {
value.DisplayLabels[label.Name] = label.Value
}
value.Labels = nil

summary.PrecisionGauges = append(summary.PrecisionGauges, value)
}
sort.Slice(summary.PrecisionGauges, func(i, j int) bool {
return summary.PrecisionGauges[i].Hash < summary.PrecisionGauges[j].Hash
})

summary.Counters = formatSamples(interval.Counters)
summary.Samples = formatSamples(interval.Samples)

Expand Down
4 changes: 4 additions & 0 deletions inmem_signal.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func (i *InmemSignal) dumpStats() {
name := i.flattenLabels(val.Name, val.Labels)
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
}
for _, val := range intv.PrecisionGauges {
name := i.flattenLabels(val.Name, val.Labels)
fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val.Value)
}
for name, vals := range intv.Points {
for _, val := range vals {
fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
Expand Down
34 changes: 34 additions & 0 deletions metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,40 @@ func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label)
m.sink.SetGaugeWithLabels(key, val, labelsFiltered)
}

func (m *Metrics) SetPrecisionGauge(key []string, val float64) {
m.SetPrecisionGaugeWithLabels(key, val, nil)
}

func (m *Metrics) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label) {
if m.HostName != "" {
if m.EnableHostnameLabel {
labels = append(labels, Label{"host", m.HostName})
} else if m.EnableHostname {
key = insert(0, m.HostName, key)
}
}
if m.EnableTypePrefix {
key = insert(0, "gauge", key)
}
if m.ServiceName != "" {
if m.EnableServiceLabel {
labels = append(labels, Label{"service", m.ServiceName})
} else {
key = insert(0, m.ServiceName, key)
}
}
allowed, labelsFiltered := m.allowMetric(key, labels)
if !allowed {
return
}
sink, ok := m.sink.(PrecisionGaugeMetricSink)
if !ok {
// Sink does not implement PrecisionGaugeMetricSink.
} else {
sink.SetPrecisionGaugeWithLabels(key, val, labelsFiltered)
}
}

func (m *Metrics) EmitKey(key []string, val float32) {
if m.EnableTypePrefix {
key = insert(0, "kv", key)
Expand Down
55 changes: 55 additions & 0 deletions metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,61 @@ func TestMetrics_SetGauge(t *testing.T) {
}
}

func TestMetrics_SetPrecisionGauge(t *testing.T) {
m, met := mockMetric()
met.SetPrecisionGauge([]string{"key"}, float64(1))
if m.getKeys()[0][0] != "key" {
t.Fatalf("")
}
if m.precisionVals[0] != 1 {
t.Fatalf("")
}

m, met = mockMetric()
labels := []Label{{"a", "b"}}
met.SetPrecisionGaugeWithLabels([]string{"key"}, float64(1), labels)
if m.getKeys()[0][0] != "key" {
t.Fatalf("")
}
if m.precisionVals[0] != 1 {
t.Fatalf("")
}
if !reflect.DeepEqual(m.labels[0], labels) {
t.Fatalf("")
}

m, met = mockMetric()
met.HostName = "test"
met.EnableHostname = true
met.SetPrecisionGauge([]string{"key"}, float64(1))
if m.getKeys()[0][0] != "test" || m.getKeys()[0][1] != "key" {
t.Fatalf("")
}
if m.precisionVals[0] != 1 {
t.Fatalf("")
}

m, met = mockMetric()
met.EnableTypePrefix = true
met.SetPrecisionGauge([]string{"key"}, float64(1))
if m.getKeys()[0][0] != "gauge" || m.getKeys()[0][1] != "key" {
t.Fatalf("")
}
if m.precisionVals[0] != 1 {
t.Fatalf("")
}

m, met = mockMetric()
met.ServiceName = "service"
met.SetPrecisionGauge([]string{"key"}, float64(1))
if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
t.Fatalf("")
}
if m.precisionVals[0] != 1 {
t.Fatalf("")
}
}

func TestMetrics_EmitKey(t *testing.T) {
m, met := mockMetric()
met.EmitKey([]string{"key"}, float32(1))
Expand Down
14 changes: 11 additions & 3 deletions prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,18 @@ func prometheusLabels(labels []metrics.Label) prometheus.Labels {
}

func (p *PrometheusSink) SetGauge(parts []string, val float32) {
p.SetGaugeWithLabels(parts, val, nil)
p.SetPrecisionGauge(parts, float64(val))
}

func (p *PrometheusSink) SetGaugeWithLabels(parts []string, val float32, labels []metrics.Label) {
p.SetPrecisionGaugeWithLabels(parts, float64(val), labels)
}

func (p *PrometheusSink) SetPrecisionGauge(parts []string, val float64) {
p.SetPrecisionGaugeWithLabels(parts, val, nil)
}

func (p *PrometheusSink) SetPrecisionGaugeWithLabels(parts []string, val float64, labels []metrics.Label) {
key, hash := flattenKey(parts, labels)
pg, ok := p.gauges.Load(hash)

Expand All @@ -285,7 +293,7 @@ func (p *PrometheusSink) SetGaugeWithLabels(parts []string, val float32, labels
// value, but since we're always setting it to time.Now(), it doesn't really matter.
if ok {
localGauge := *pg.(*gauge)
localGauge.Set(float64(val))
localGauge.Set(val)
localGauge.updatedAt = time.Now()
p.gauges.Store(hash, &localGauge)

Expand All @@ -301,7 +309,7 @@ func (p *PrometheusSink) SetGaugeWithLabels(parts []string, val float32, labels
Help: help,
ConstLabels: prometheusLabels(labels),
})
g.Set(float64(val))
g.Set(val)
pg = &gauge{
Gauge: g,
updatedAt: time.Now(),
Expand Down
21 changes: 21 additions & 0 deletions prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,27 @@ func TestSetGauge(t *testing.T) {
}
}

func TestSetPrecisionGauge(t *testing.T) {
q := make(chan string)
server := fakeServer(q)
defer server.Close()
u, err := url.Parse(server.URL)
if err != nil {
log.Fatal(err)
}
host := u.Hostname() + ":" + u.Port()
sink, err := NewPrometheusPushSink(host, time.Second, "pushtest")
metricsConf := metrics.DefaultConfig("default")
metricsConf.HostName = MockGetHostname()
metricsConf.EnableHostnameLabel = true
metrics.NewGlobal(metricsConf, sink)
metrics.SetPrecisionGauge([]string{"one", "two"}, 42)
response := <-q
if response != "ok" {
t.Fatal(response)
}
}

func TestDefinitionsWithLabels(t *testing.T) {
gaugeDef := GaugeDefinition{
Name: []string{"my", "test", "gauge"},
Expand Down
Loading

0 comments on commit 8586014

Please sign in to comment.