github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/metrics.go (about) 1 // +build !js 2 3 package goa 4 5 import ( 6 "regexp" 7 "strings" 8 "sync/atomic" 9 "time" 10 11 "github.com/armon/go-metrics" 12 ) 13 14 const ( 15 allMatcher string = "*/*" 16 allReplacement string = "all" 17 normalizedToken string = "_" 18 ) 19 20 var ( 21 // metriks atomic value storage 22 metriks atomic.Value 23 24 // invalidCharactersRE is the invert match of validCharactersRE 25 invalidCharactersRE = regexp.MustCompile(`[\*/]`) 26 27 // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/desc.go 28 validCharactersRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`) 29 ) 30 31 func init() { 32 m, err := metrics.New(metrics.DefaultConfig("service"), NewNoOpSink()) 33 if err != nil { 34 panic("Unable to instantiate default metrics sink") 35 } 36 37 SetMetrics(m) 38 } 39 40 // NewNoOpSink returns a NOOP sink. 41 func NewNoOpSink() metrics.MetricSink { 42 return &NoOpSink{} 43 } 44 45 // NoOpSink default NOOP metrics recorder 46 type NoOpSink struct{} 47 48 // SetGauge method 49 func (md *NoOpSink) SetGauge(key []string, val float32) {} 50 51 // EmitKey method 52 func (md *NoOpSink) EmitKey(key []string, val float32) {} 53 54 // IncrCounter method 55 func (md *NoOpSink) IncrCounter(key []string, val float32) {} 56 57 // AddSample method 58 func (md *NoOpSink) AddSample(key []string, val float32) {} 59 60 // MeasureSince method 61 func (md *NoOpSink) MeasureSince(key []string, start time.Time) {} 62 63 // NewMetrics initializes goa's metrics instance with the supplied 64 // configuration and metrics sink 65 // This method is deprecated and SetMetrics should be used instead. 66 func NewMetrics(conf *metrics.Config, sink metrics.MetricSink) (err error) { 67 m, err := metrics.NewGlobal(conf, sink) 68 SetMetrics(m) 69 70 return nil 71 } 72 73 // SetMetrics initializes goa's metrics instance with the supplied metrics adapter interface. 74 func SetMetrics(m *metrics.Metrics) { 75 metriks.Store(m) 76 } 77 78 // AddSample adds a sample to an aggregated metric 79 // reporting count, min, max, mean, and std deviation 80 // Usage: 81 // AddSample([]string{"my","namespace","key"}, 15.0) 82 func AddSample(key []string, val float32) { 83 normalizeKeys(key) 84 85 metriks.Load().(*metrics.Metrics).AddSample(key, val) 86 } 87 88 // EmitKey emits a key/value pair 89 // Usage: 90 // EmitKey([]string{"my","namespace","key"}, 15.0) 91 func EmitKey(key []string, val float32) { 92 normalizeKeys(key) 93 94 metriks.Load().(*metrics.Metrics).EmitKey(key, val) 95 } 96 97 // IncrCounter increments the counter named by `key` 98 // Usage: 99 // IncrCounter([]key{"my","namespace","counter"}, 1.0) 100 func IncrCounter(key []string, val float32) { 101 normalizeKeys(key) 102 103 metriks.Load().(*metrics.Metrics).IncrCounter(key, val) 104 } 105 106 // MeasureSince creates a timing metric that records 107 // the duration of elapsed time since `start` 108 // Usage: 109 // MeasureSince([]string{"my","namespace","action"}, time.Now()) 110 // Frequently used in a defer: 111 // defer MeasureSince([]string{"my","namespace","action"}, time.Now()) 112 func MeasureSince(key []string, start time.Time) { 113 normalizeKeys(key) 114 115 metriks.Load().(*metrics.Metrics).MeasureSince(key, start) 116 } 117 118 // SetGauge sets the named gauge to the specified value 119 // Usage: 120 // SetGauge([]string{"my","namespace"}, 2.0) 121 func SetGauge(key []string, val float32) { 122 normalizeKeys(key) 123 124 metriks.Load().(*metrics.Metrics).SetGauge(key, val) 125 } 126 127 // This function is used to make metric names safe for all metric services. Specifically, prometheus does 128 // not support * or / in metric names. 129 func normalizeKeys(key []string) { 130 for i, k := range key { 131 if !validCharactersRE.MatchString(k) { 132 // first replace */* with all 133 k = strings.Replace(k, allMatcher, allReplacement, -1) 134 135 // now replace all other invalid characters with a safe one. 136 key[i] = invalidCharactersRE.ReplaceAllString(k, normalizedToken) 137 } 138 } 139 }