2016-02-13 00:50:37 +00:00
|
|
|
package metrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
2017-08-08 19:33:47 +00:00
|
|
|
"sync"
|
2017-05-22 19:39:36 +00:00
|
|
|
"sync/atomic"
|
2016-02-13 00:50:37 +00:00
|
|
|
"time"
|
2017-08-07 23:37:52 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/go-immutable-radix"
|
2016-02-13 00:50:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Config is used to configure metrics settings
|
|
|
|
type Config struct {
|
2018-04-05 16:21:32 +00:00
|
|
|
ServiceName string // Prefixed with keys to separate services
|
2016-02-13 00:50:37 +00:00
|
|
|
HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
|
|
|
|
EnableHostname bool // Enable prefixing gauge values with hostname
|
2017-08-07 23:37:52 +00:00
|
|
|
EnableHostnameLabel bool // Enable adding hostname to labels
|
|
|
|
EnableServiceLabel bool // Enable adding service to labels
|
2016-02-13 00:50:37 +00:00
|
|
|
EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
|
|
|
|
EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
|
|
|
|
TimerGranularity time.Duration // Granularity of timers.
|
|
|
|
ProfileInterval time.Duration // Interval to profile runtime metrics
|
2017-08-08 19:33:47 +00:00
|
|
|
|
|
|
|
AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
|
|
|
|
BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
|
|
|
|
FilterDefault bool // Whether to allow metrics by default
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Metrics represents an instance of a metrics sink that can
|
|
|
|
// be used to emit
|
|
|
|
type Metrics struct {
|
|
|
|
Config
|
2017-08-08 19:33:47 +00:00
|
|
|
lastNumGC uint32
|
|
|
|
sink MetricSink
|
|
|
|
filter *iradix.Tree
|
|
|
|
filterLock sync.RWMutex
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shared global metrics instance
|
2017-06-01 21:52:26 +00:00
|
|
|
var globalMetrics atomic.Value // *Metrics
|
2016-02-13 00:50:37 +00:00
|
|
|
|
|
|
|
func init() {
|
2017-06-01 21:52:26 +00:00
|
|
|
// Initialize to a blackhole sink to avoid errors
|
|
|
|
globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultConfig provides a sane default configuration
|
|
|
|
func DefaultConfig(serviceName string) *Config {
|
|
|
|
c := &Config{
|
|
|
|
ServiceName: serviceName, // Use client provided service
|
|
|
|
HostName: "",
|
|
|
|
EnableHostname: true, // Enable hostname prefix
|
|
|
|
EnableRuntimeMetrics: true, // Enable runtime profiling
|
|
|
|
EnableTypePrefix: false, // Disable type prefix
|
|
|
|
TimerGranularity: time.Millisecond, // Timers are in milliseconds
|
|
|
|
ProfileInterval: time.Second, // Poll runtime every second
|
2017-08-07 23:37:52 +00:00
|
|
|
FilterDefault: true, // Don't filter metrics by default
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try to get the hostname
|
|
|
|
name, _ := os.Hostname()
|
|
|
|
c.HostName = name
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// New is used to create a new instance of Metrics
|
|
|
|
func New(conf *Config, sink MetricSink) (*Metrics, error) {
|
|
|
|
met := &Metrics{}
|
|
|
|
met.Config = *conf
|
|
|
|
met.sink = sink
|
2017-08-08 19:33:47 +00:00
|
|
|
met.UpdateFilter(conf.AllowedPrefixes, conf.BlockedPrefixes)
|
2016-02-13 00:50:37 +00:00
|
|
|
|
|
|
|
// Start the runtime collector
|
|
|
|
if conf.EnableRuntimeMetrics {
|
|
|
|
go met.collectStats()
|
|
|
|
}
|
|
|
|
return met, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewGlobal is the same as New, but it assigns the metrics object to be
|
|
|
|
// used globally as well as returning it.
|
|
|
|
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
|
|
|
|
metrics, err := New(conf, sink)
|
|
|
|
if err == nil {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Store(metrics)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
return metrics, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Proxy all the methods to the globalMetrics instance
|
|
|
|
func SetGauge(key []string, val float32) {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Load().(*Metrics).SetGauge(key, val)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
|
|
|
|
globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
|
|
|
|
}
|
|
|
|
|
2016-02-13 00:50:37 +00:00
|
|
|
func EmitKey(key []string, val float32) {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Load().(*Metrics).EmitKey(key, val)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func IncrCounter(key []string, val float32) {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Load().(*Metrics).IncrCounter(key, val)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
|
|
|
|
globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
|
|
|
|
}
|
|
|
|
|
2016-02-13 00:50:37 +00:00
|
|
|
func AddSample(key []string, val float32) {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Load().(*Metrics).AddSample(key, val)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
2017-08-07 23:37:52 +00:00
|
|
|
func AddSampleWithLabels(key []string, val float32, labels []Label) {
|
|
|
|
globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
|
|
|
|
}
|
|
|
|
|
2016-02-13 00:50:37 +00:00
|
|
|
func MeasureSince(key []string, start time.Time) {
|
2017-06-01 21:52:26 +00:00
|
|
|
globalMetrics.Load().(*Metrics).MeasureSince(key, start)
|
2016-02-13 00:50:37 +00:00
|
|
|
}
|
2017-08-07 23:37:52 +00:00
|
|
|
|
|
|
|
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
|
|
|
|
globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
|
|
|
|
}
|
2017-08-08 19:33:47 +00:00
|
|
|
|
|
|
|
func UpdateFilter(allow, block []string) {
|
|
|
|
globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
|
|
|
|
}
|