Codebase list golang-github-go-kit-kit / 8dbce0d metrics / provider / providers.go
8dbce0d

Tree @8dbce0d (Download .tar.gz)

providers.go @8dbce0draw · history · blame

package provider

import (
	"errors"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	kitexp "github.com/go-kit/kit/metrics/expvar"
	"github.com/go-kit/kit/metrics/graphite"
	kitprom "github.com/go-kit/kit/metrics/prometheus"
	"github.com/go-kit/kit/metrics/statsd"
	"github.com/prometheus/client_golang/prometheus"
)

// Provider represents a union set of constructors and lifecycle management
// functions for each supported metrics backend. It should be used by those
// who need to easily swap out implementations, e.g. dynamically, or at a
// single point in an intermediating framework.
type Provider interface {
	NewCounter(name string) metrics.Counter
	NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error)
	NewGauge(name string) metrics.Gauge

	Stop()
}

// NewGraphiteProvider will return a Provider implementation that is a simple
// wrapper around a graphite.Emitter. All metrics names will get prefixed
// with the given value and data will be emitted once every interval.
// If no network value is given, it will get defaulted to "udp".
func NewGraphiteProvider(addr, network, prefix string, interval time.Duration, logger log.Logger) (Provider, error) {
	if addr == "" {
		return nil, errors.New("graphite server address is required")
	}
	if network == "" {
		network = "udp"
	}
	e := graphite.NewEmitter(addr, network, prefix, interval, logger)
	return &graphiteProvider{Emitter: e}, nil
}

type graphiteProvider struct {
	*graphite.Emitter
}

// NewStatsdProvider will return a Provider implementation that is a simple
// wrapper around a statsd.Emitter. All metrics names will get prefixed
// with the given value and data will be emitted once every interval
// or when the buffer has reached its max size.
// If no network value is given, it will get defaulted to "udp".
func NewStatsdProvider(addr, network, prefix string, interval time.Duration, logger log.Logger) (Provider, error) {
	if addr == "" {
		return nil, errors.New("statsd server address is required")
	}
	if network == "" {
		network = "udp"
	}
	e := statsd.NewEmitter(addr, network, prefix, interval, logger)
	return &statsdProvider{e: e}, nil
}

type statsdProvider struct {
	e *statsd.Emitter
}

func (s *statsdProvider) NewCounter(name string) metrics.Counter {
	return s.e.NewCounter(name)
}

func (s *statsdProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) {
	return s.e.NewHistogram(name), nil
}

func (s *statsdProvider) NewGauge(name string) metrics.Gauge {
	return s.e.NewGauge(name)
}

// Stop will call the underlying statsd.Emitter's Stop method.
func (s *statsdProvider) Stop() {
	s.e.Stop()
}

// NewExpvarProvider is a very thin wrapper over the expvar package.
// If a prefix is provided, it will prefix in metric names.
func NewExpvarProvider(prefix string) Provider {
	return &expvarProvider{prefix: prefix}
}

type expvarProvider struct {
	prefix string
}

func (e *expvarProvider) pref(name string) string {
	return e.prefix + name
}

func (e *expvarProvider) NewCounter(name string) metrics.Counter {
	return kitexp.NewCounter(e.pref(name))
}

func (e *expvarProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) {
	return kitexp.NewHistogram(e.pref(name), min, max, sigfigs, quantiles...), nil
}

func (e *expvarProvider) NewGauge(name string) metrics.Gauge {
	return kitexp.NewGauge(e.pref(name))
}

// Stop is a no-op.
func (e *expvarProvider) Stop() {}

type prometheusProvider struct {
	ns string
}

// NewPrometheusProvider will use the given namespace
// for all metrics' Opts.
func NewPrometheusProvider(namespace string) Provider {
	return &prometheusProvider{ns: namespace}
}

func (p *prometheusProvider) NewCounter(name string) metrics.Counter {
	opts := prometheus.CounterOpts{
		Namespace: p.ns,
		Name:      name,
	}
	return kitprom.NewCounter(opts, nil)
}

// NewHistogram ignores all NewHistogram parameters but `name`.
func (p *prometheusProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) {
	opts := prometheus.HistogramOpts{
		Namespace: p.ns,
		Name:      name,
	}
	return kitprom.NewHistogram(opts, nil), nil
}

func (p *prometheusProvider) NewGauge(name string) metrics.Gauge {
	opts := prometheus.GaugeOpts{
		Namespace: p.ns,
		Name:      name,
	}
	return kitprom.NewGauge(opts, nil)
}

// Stop is a no-op
func (p *prometheusProvider) Stop() {}