Codebase list golang-github-go-kit-kit / upstream/0.6.0 metrics / generic / generic.go
upstream/0.6.0

Tree @upstream/0.6.0 (Download .tar.gz)

generic.go @upstream/0.6.0

08bbec4
 
 
 
 
 
6e578a4
 
08bbec4
 
 
 
 
 
8114e4a
 
08bbec4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
839f598
08bbec4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a61ec96
08bbec4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
839f598
08bbec4
 
 
 
 
 
 
 
 
 
32d7a0b
 
 
 
 
 
 
 
 
 
 
 
 
 
08bbec4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f2e95e8
08bbec4
 
 
 
 
 
 
f2e95e8
08bbec4
 
 
 
 
 
839f598
 
 
08bbec4
 
 
 
 
f2e95e8
 
08bbec4
 
 
 
 
f2e95e8
 
08bbec4
 
 
 
 
 
 
 
6e578a4
 
 
f2e95e8
 
6e578a4
 
 
f2e95e8
 
 
 
 
 
6e578a4
 
 
 
 
 
 
 
 
 
 
08bbec4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fd567d
08bbec4
 
 
 
 
 
 
// Package generic implements generic versions of each of the metric types. They
// can be embedded by other implementations, and converted to specific formats
// as necessary.
package generic

import (
	"fmt"
	"io"
	"math"
	"sync"
	"sync/atomic"

	"github.com/VividCortex/gohistogram"

	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/internal/lv"
)

// Counter is an in-memory implementation of a Counter.
type Counter struct {
	Name string
	lvs  lv.LabelValues
	bits uint64
}

// NewCounter returns a new, usable Counter.
func NewCounter(name string) *Counter {
	return &Counter{
		Name: name,
	}
}

// With implements Counter.
func (c *Counter) With(labelValues ...string) metrics.Counter {
	return &Counter{
		Name: c.Name,
		bits: atomic.LoadUint64(&c.bits),
		lvs:  c.lvs.With(labelValues...),
	}
}

// Add implements Counter.
func (c *Counter) Add(delta float64) {
	for {
		var (
			old  = atomic.LoadUint64(&c.bits)
			newf = math.Float64frombits(old) + delta
			new  = math.Float64bits(newf)
		)
		if atomic.CompareAndSwapUint64(&c.bits, old, new) {
			break
		}
	}
}

// Value returns the current value of the counter.
func (c *Counter) Value() float64 {
	return math.Float64frombits(atomic.LoadUint64(&c.bits))
}

// ValueReset returns the current value of the counter, and resets it to zero.
// This is useful for metrics backends whose counter aggregations expect deltas,
// like Graphite.
func (c *Counter) ValueReset() float64 {
	for {
		var (
			old  = atomic.LoadUint64(&c.bits)
			newf = 0.0
			new  = math.Float64bits(newf)
		)
		if atomic.CompareAndSwapUint64(&c.bits, old, new) {
			return math.Float64frombits(old)
		}
	}
}

// LabelValues returns the set of label values attached to the counter.
func (c *Counter) LabelValues() []string {
	return c.lvs
}

// Gauge is an in-memory implementation of a Gauge.
type Gauge struct {
	Name string
	lvs  lv.LabelValues
	bits uint64
}

// NewGauge returns a new, usable Gauge.
func NewGauge(name string) *Gauge {
	return &Gauge{
		Name: name,
	}
}

// With implements Gauge.
func (g *Gauge) With(labelValues ...string) metrics.Gauge {
	return &Gauge{
		Name: g.Name,
		bits: atomic.LoadUint64(&g.bits),
		lvs:  g.lvs.With(labelValues...),
	}
}

// Set implements Gauge.
func (g *Gauge) Set(value float64) {
	atomic.StoreUint64(&g.bits, math.Float64bits(value))
}

// Add implements metrics.Gauge.
func (g *Gauge) Add(delta float64) {
	for {
		var (
			old  = atomic.LoadUint64(&g.bits)
			newf = math.Float64frombits(old) + delta
			new  = math.Float64bits(newf)
		)
		if atomic.CompareAndSwapUint64(&g.bits, old, new) {
			break
		}
	}
}

// Value returns the current value of the gauge.
func (g *Gauge) Value() float64 {
	return math.Float64frombits(atomic.LoadUint64(&g.bits))
}

// LabelValues returns the set of label values attached to the gauge.
func (g *Gauge) LabelValues() []string {
	return g.lvs
}

// Histogram is an in-memory implementation of a streaming histogram, based on
// VividCortex/gohistogram. It dynamically computes quantiles, so it's not
// suitable for aggregation.
type Histogram struct {
	Name string
	lvs  lv.LabelValues
	h    *safeHistogram
}

// NewHistogram returns a numeric histogram based on VividCortex/gohistogram. A
// good default value for buckets is 50.
func NewHistogram(name string, buckets int) *Histogram {
	return &Histogram{
		Name: name,
		h:    &safeHistogram{Histogram: gohistogram.NewHistogram(buckets)},
	}
}

// With implements Histogram.
func (h *Histogram) With(labelValues ...string) metrics.Histogram {
	return &Histogram{
		Name: h.Name,
		lvs:  h.lvs.With(labelValues...),
		h:    h.h,
	}
}

// Observe implements Histogram.
func (h *Histogram) Observe(value float64) {
	h.h.Lock()
	defer h.h.Unlock()
	h.h.Add(value)
}

// Quantile returns the value of the quantile q, 0.0 < q < 1.0.
func (h *Histogram) Quantile(q float64) float64 {
	h.h.RLock()
	defer h.h.RUnlock()
	return h.h.Quantile(q)
}

// LabelValues returns the set of label values attached to the histogram.
func (h *Histogram) LabelValues() []string {
	return h.lvs
}

// Print writes a string representation of the histogram to the passed writer.
// Useful for printing to a terminal.
func (h *Histogram) Print(w io.Writer) {
	h.h.RLock()
	defer h.h.RUnlock()
	fmt.Fprintf(w, h.h.String())
}

// safeHistogram exists as gohistogram.Histogram is not goroutine-safe.
type safeHistogram struct {
	sync.RWMutex
	gohistogram.Histogram
}

// Bucket is a range in a histogram which aggregates observations.
type Bucket struct {
	From, To, Count int64
}

// Quantile is a pair of a quantile (0..100) and its observed maximum value.
type Quantile struct {
	Quantile int // 0..100
	Value    int64
}

// SimpleHistogram is an in-memory implementation of a Histogram. It only tracks
// an approximate moving average, so is likely too naïve for many use cases.
type SimpleHistogram struct {
	mtx sync.RWMutex
	lvs lv.LabelValues
	avg float64
	n   uint64
}

// NewSimpleHistogram returns a SimpleHistogram, ready for observations.
func NewSimpleHistogram() *SimpleHistogram {
	return &SimpleHistogram{}
}

// With implements Histogram.
func (h *SimpleHistogram) With(labelValues ...string) metrics.Histogram {
	return &SimpleHistogram{
		lvs: h.lvs.With(labelValues...),
		avg: h.avg,
		n:   h.n,
	}
}

// Observe implements Histogram.
func (h *SimpleHistogram) Observe(value float64) {
	h.mtx.Lock()
	defer h.mtx.Unlock()
	h.n++
	h.avg -= h.avg / float64(h.n)
	h.avg += value / float64(h.n)
}

// ApproximateMovingAverage returns the approximate moving average of observations.
func (h *SimpleHistogram) ApproximateMovingAverage() float64 {
	h.mtx.RLock()
	defer h.mtx.RUnlock()
	return h.avg
}

// LabelValues returns the set of label values attached to the histogram.
func (h *SimpleHistogram) LabelValues() []string {
	return h.lvs
}