github.com/codingfuture/orig-energi3@v0.8.4/metrics/librato/librato.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2018 The go-ethereum Authors 3 // This file is part of the Energi Core library. 4 // 5 // The Energi Core library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The Energi Core library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 17 18 package librato 19 20 import ( 21 "fmt" 22 "log" 23 "math" 24 "regexp" 25 "time" 26 27 "github.com/ethereum/go-ethereum/metrics" 28 ) 29 30 // a regexp for extracting the unit from time.Duration.String 31 var unitRegexp = regexp.MustCompile(`[^\\d]+$`) 32 33 // a helper that turns a time.Duration into librato display attributes for timer metrics 34 func translateTimerAttributes(d time.Duration) (attrs map[string]interface{}) { 35 attrs = make(map[string]interface{}) 36 attrs[DisplayTransform] = fmt.Sprintf("x/%d", int64(d)) 37 attrs[DisplayUnitsShort] = string(unitRegexp.Find([]byte(d.String()))) 38 return 39 } 40 41 type Reporter struct { 42 Email, Token string 43 Namespace string 44 Source string 45 Interval time.Duration 46 Registry metrics.Registry 47 Percentiles []float64 // percentiles to report on histogram metrics 48 TimerAttributes map[string]interface{} // units in which timers will be displayed 49 intervalSec int64 50 } 51 52 func NewReporter(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) *Reporter { 53 return &Reporter{e, t, "", s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)} 54 } 55 56 func Librato(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) { 57 NewReporter(r, d, e, t, s, p, u).Run() 58 } 59 60 func (rep *Reporter) Run() { 61 log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015") 62 ticker := time.Tick(rep.Interval) 63 metricsApi := &LibratoClient{rep.Email, rep.Token} 64 for now := range ticker { 65 var metrics Batch 66 var err error 67 if metrics, err = rep.BuildRequest(now, rep.Registry); err != nil { 68 log.Printf("ERROR constructing librato request body %s", err) 69 continue 70 } 71 if err := metricsApi.PostMetrics(metrics); err != nil { 72 log.Printf("ERROR sending metrics to librato %s", err) 73 continue 74 } 75 } 76 } 77 78 // calculate sum of squares from data provided by metrics.Histogram 79 // see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods 80 func sumSquares(s metrics.Sample) float64 { 81 count := float64(s.Count()) 82 sumSquared := math.Pow(count*s.Mean(), 2) 83 sumSquares := math.Pow(count*s.StdDev(), 2) + sumSquared/count 84 if math.IsNaN(sumSquares) { 85 return 0.0 86 } 87 return sumSquares 88 } 89 func sumSquaresTimer(t metrics.Timer) float64 { 90 count := float64(t.Count()) 91 sumSquared := math.Pow(count*t.Mean(), 2) 92 sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count 93 if math.IsNaN(sumSquares) { 94 return 0.0 95 } 96 return sumSquares 97 } 98 99 func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) { 100 snapshot = Batch{ 101 // coerce timestamps to a stepping fn so that they line up in Librato graphs 102 MeasureTime: (now.Unix() / rep.intervalSec) * rep.intervalSec, 103 Source: rep.Source, 104 } 105 snapshot.Gauges = make([]Measurement, 0) 106 snapshot.Counters = make([]Measurement, 0) 107 histogramGaugeCount := 1 + len(rep.Percentiles) 108 r.Each(func(name string, metric interface{}) { 109 if rep.Namespace != "" { 110 name = fmt.Sprintf("%s.%s", rep.Namespace, name) 111 } 112 measurement := Measurement{} 113 measurement[Period] = rep.Interval.Seconds() 114 switch m := metric.(type) { 115 case metrics.Counter: 116 if m.Count() > 0 { 117 measurement[Name] = fmt.Sprintf("%s.%s", name, "count") 118 measurement[Value] = float64(m.Count()) 119 measurement[Attributes] = map[string]interface{}{ 120 DisplayUnitsLong: Operations, 121 DisplayUnitsShort: OperationsShort, 122 DisplayMin: "0", 123 } 124 snapshot.Counters = append(snapshot.Counters, measurement) 125 } 126 case metrics.Gauge: 127 measurement[Name] = name 128 measurement[Value] = float64(m.Value()) 129 snapshot.Gauges = append(snapshot.Gauges, measurement) 130 case metrics.GaugeFloat64: 131 measurement[Name] = name 132 measurement[Value] = m.Value() 133 snapshot.Gauges = append(snapshot.Gauges, measurement) 134 case metrics.Histogram: 135 if m.Count() > 0 { 136 gauges := make([]Measurement, histogramGaugeCount) 137 s := m.Sample() 138 measurement[Name] = fmt.Sprintf("%s.%s", name, "hist") 139 measurement[Count] = uint64(s.Count()) 140 measurement[Max] = float64(s.Max()) 141 measurement[Min] = float64(s.Min()) 142 measurement[Sum] = float64(s.Sum()) 143 measurement[SumSquares] = sumSquares(s) 144 gauges[0] = measurement 145 for i, p := range rep.Percentiles { 146 gauges[i+1] = Measurement{ 147 Name: fmt.Sprintf("%s.%.2f", measurement[Name], p), 148 Value: s.Percentile(p), 149 Period: measurement[Period], 150 } 151 } 152 snapshot.Gauges = append(snapshot.Gauges, gauges...) 153 } 154 case metrics.Meter: 155 measurement[Name] = name 156 measurement[Value] = float64(m.Count()) 157 snapshot.Counters = append(snapshot.Counters, measurement) 158 snapshot.Gauges = append(snapshot.Gauges, 159 Measurement{ 160 Name: fmt.Sprintf("%s.%s", name, "1min"), 161 Value: m.Rate1(), 162 Period: int64(rep.Interval.Seconds()), 163 Attributes: map[string]interface{}{ 164 DisplayUnitsLong: Operations, 165 DisplayUnitsShort: OperationsShort, 166 DisplayMin: "0", 167 }, 168 }, 169 Measurement{ 170 Name: fmt.Sprintf("%s.%s", name, "5min"), 171 Value: m.Rate5(), 172 Period: int64(rep.Interval.Seconds()), 173 Attributes: map[string]interface{}{ 174 DisplayUnitsLong: Operations, 175 DisplayUnitsShort: OperationsShort, 176 DisplayMin: "0", 177 }, 178 }, 179 Measurement{ 180 Name: fmt.Sprintf("%s.%s", name, "15min"), 181 Value: m.Rate15(), 182 Period: int64(rep.Interval.Seconds()), 183 Attributes: map[string]interface{}{ 184 DisplayUnitsLong: Operations, 185 DisplayUnitsShort: OperationsShort, 186 DisplayMin: "0", 187 }, 188 }, 189 ) 190 case metrics.Timer: 191 measurement[Name] = name 192 measurement[Value] = float64(m.Count()) 193 snapshot.Counters = append(snapshot.Counters, measurement) 194 if m.Count() > 0 { 195 libratoName := fmt.Sprintf("%s.%s", name, "timer.mean") 196 gauges := make([]Measurement, histogramGaugeCount) 197 gauges[0] = Measurement{ 198 Name: libratoName, 199 Count: uint64(m.Count()), 200 Sum: m.Mean() * float64(m.Count()), 201 Max: float64(m.Max()), 202 Min: float64(m.Min()), 203 SumSquares: sumSquaresTimer(m), 204 Period: int64(rep.Interval.Seconds()), 205 Attributes: rep.TimerAttributes, 206 } 207 for i, p := range rep.Percentiles { 208 gauges[i+1] = Measurement{ 209 Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100), 210 Value: m.Percentile(p), 211 Period: int64(rep.Interval.Seconds()), 212 Attributes: rep.TimerAttributes, 213 } 214 } 215 snapshot.Gauges = append(snapshot.Gauges, gauges...) 216 snapshot.Gauges = append(snapshot.Gauges, 217 Measurement{ 218 Name: fmt.Sprintf("%s.%s", name, "rate.1min"), 219 Value: m.Rate1(), 220 Period: int64(rep.Interval.Seconds()), 221 Attributes: map[string]interface{}{ 222 DisplayUnitsLong: Operations, 223 DisplayUnitsShort: OperationsShort, 224 DisplayMin: "0", 225 }, 226 }, 227 Measurement{ 228 Name: fmt.Sprintf("%s.%s", name, "rate.5min"), 229 Value: m.Rate5(), 230 Period: int64(rep.Interval.Seconds()), 231 Attributes: map[string]interface{}{ 232 DisplayUnitsLong: Operations, 233 DisplayUnitsShort: OperationsShort, 234 DisplayMin: "0", 235 }, 236 }, 237 Measurement{ 238 Name: fmt.Sprintf("%s.%s", name, "rate.15min"), 239 Value: m.Rate15(), 240 Period: int64(rep.Interval.Seconds()), 241 Attributes: map[string]interface{}{ 242 DisplayUnitsLong: Operations, 243 DisplayUnitsShort: OperationsShort, 244 DisplayMin: "0", 245 }, 246 }, 247 ) 248 } 249 } 250 }) 251 return 252 }