blob: 32a28c483785a7a114a3249491a5488f8d301a6d [file] [log] [blame]
Scott Baker2d897982019-09-24 11:50:08 -07001package metrics
2
3import (
4 "os"
5 "sync"
6 "sync/atomic"
7 "time"
8
9 "github.com/hashicorp/go-immutable-radix"
10)
11
12// Config is used to configure metrics settings
13type Config struct {
14 ServiceName string // Prefixed with keys to separate services
15 HostName string // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
16 EnableHostname bool // Enable prefixing gauge values with hostname
17 EnableHostnameLabel bool // Enable adding hostname to labels
18 EnableServiceLabel bool // Enable adding service to labels
19 EnableRuntimeMetrics bool // Enables profiling of runtime metrics (GC, Goroutines, Memory)
20 EnableTypePrefix bool // Prefixes key with a type ("counter", "gauge", "timer")
21 TimerGranularity time.Duration // Granularity of timers.
22 ProfileInterval time.Duration // Interval to profile runtime metrics
23
24 AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
25 BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
26 AllowedLabels []string // A list of metric labels to allow, with '.' as the separator
27 BlockedLabels []string // A list of metric labels to block, with '.' as the separator
28 FilterDefault bool // Whether to allow metrics by default
29}
30
31// Metrics represents an instance of a metrics sink that can
32// be used to emit
33type Metrics struct {
34 Config
35 lastNumGC uint32
36 sink MetricSink
37 filter *iradix.Tree
38 allowedLabels map[string]bool
39 blockedLabels map[string]bool
40 filterLock sync.RWMutex // Lock filters and allowedLabels/blockedLabels access
41}
42
43// Shared global metrics instance
44var globalMetrics atomic.Value // *Metrics
45
46func init() {
47 // Initialize to a blackhole sink to avoid errors
48 globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
49}
50
51// DefaultConfig provides a sane default configuration
52func DefaultConfig(serviceName string) *Config {
53 c := &Config{
54 ServiceName: serviceName, // Use client provided service
55 HostName: "",
56 EnableHostname: true, // Enable hostname prefix
57 EnableRuntimeMetrics: true, // Enable runtime profiling
58 EnableTypePrefix: false, // Disable type prefix
59 TimerGranularity: time.Millisecond, // Timers are in milliseconds
60 ProfileInterval: time.Second, // Poll runtime every second
61 FilterDefault: true, // Don't filter metrics by default
62 }
63
64 // Try to get the hostname
65 name, _ := os.Hostname()
66 c.HostName = name
67 return c
68}
69
70// New is used to create a new instance of Metrics
71func New(conf *Config, sink MetricSink) (*Metrics, error) {
72 met := &Metrics{}
73 met.Config = *conf
74 met.sink = sink
75 met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedPrefixes, conf.AllowedLabels, conf.BlockedLabels)
76
77 // Start the runtime collector
78 if conf.EnableRuntimeMetrics {
79 go met.collectStats()
80 }
81 return met, nil
82}
83
84// NewGlobal is the same as New, but it assigns the metrics object to be
85// used globally as well as returning it.
86func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
87 metrics, err := New(conf, sink)
88 if err == nil {
89 globalMetrics.Store(metrics)
90 }
91 return metrics, err
92}
93
94// Proxy all the methods to the globalMetrics instance
95func SetGauge(key []string, val float32) {
96 globalMetrics.Load().(*Metrics).SetGauge(key, val)
97}
98
99func SetGaugeWithLabels(key []string, val float32, labels []Label) {
100 globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
101}
102
103func EmitKey(key []string, val float32) {
104 globalMetrics.Load().(*Metrics).EmitKey(key, val)
105}
106
107func IncrCounter(key []string, val float32) {
108 globalMetrics.Load().(*Metrics).IncrCounter(key, val)
109}
110
111func IncrCounterWithLabels(key []string, val float32, labels []Label) {
112 globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
113}
114
115func AddSample(key []string, val float32) {
116 globalMetrics.Load().(*Metrics).AddSample(key, val)
117}
118
119func AddSampleWithLabels(key []string, val float32, labels []Label) {
120 globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
121}
122
123func MeasureSince(key []string, start time.Time) {
124 globalMetrics.Load().(*Metrics).MeasureSince(key, start)
125}
126
127func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
128 globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
129}
130
131func UpdateFilter(allow, block []string) {
132 globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
133}
134
135// UpdateFilterAndLabels set allow/block prefixes of metrics while allowedLabels
136// and blockedLabels - when not nil - allow filtering of labels in order to
137// block/allow globally labels (especially useful when having large number of
138// values for a given label). See README.md for more information about usage.
139func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
140 globalMetrics.Load().(*Metrics).UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
141}