|
|
@@ -0,0 +1,139 @@
|
|
|
+package librato
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "github.com/rcrowley/go-metrics"
|
|
|
+ "github.com/samuel/go-librato/librato"
|
|
|
+ "log"
|
|
|
+ "math"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type LibratoReporter struct {
|
|
|
+ Email, Token string
|
|
|
+ Source string
|
|
|
+ Interval time.Duration
|
|
|
+ Registry metrics.Registry
|
|
|
+ Percentiles []float64
|
|
|
+}
|
|
|
+
|
|
|
+func (self *LibratoReporter) Run() {
|
|
|
+ ticker := time.Tick(self.Interval * time.Millisecond)
|
|
|
+ metricsApi := &librato.Metrics{self.Email, self.Token}
|
|
|
+ for now := range ticker {
|
|
|
+ var metrics *librato.MetricsFormat
|
|
|
+ var err error
|
|
|
+ if metrics, err = self.BuildRequest(now, self.Registry); err != nil {
|
|
|
+ log.Printf("ERROR constructing librato request body %s", err)
|
|
|
+ }
|
|
|
+ if err := metricsApi.SendMetrics(metrics); err != nil {
|
|
|
+ log.Printf("ERROR sending metrics to librato %s", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// calculate sum of squares from data provided by metrics.Histogram
|
|
|
+// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
|
|
|
+func sumSquares(m metrics.Histogram) float64 {
|
|
|
+ count := float64(m.Count())
|
|
|
+ sum := m.Mean() * float64(m.Count())
|
|
|
+ sumSquared := math.Pow(float64(sum), 2)
|
|
|
+ sumSquares := math.Pow(count*m.StdDev(), 2) + sumSquared/float64(m.Count())
|
|
|
+ if math.IsNaN(sumSquares) {
|
|
|
+ return 0.0
|
|
|
+ }
|
|
|
+ return sumSquared
|
|
|
+}
|
|
|
+func sumSquaresTimer(m metrics.Timer) float64 {
|
|
|
+ count := float64(m.Count())
|
|
|
+ sum := m.Mean() * float64(m.Count())
|
|
|
+ sumSquared := math.Pow(float64(sum), 2)
|
|
|
+ sumSquares := math.Pow(count*m.StdDev(), 2) + sumSquared/float64(m.Count())
|
|
|
+ if math.IsNaN(sumSquares) {
|
|
|
+ return 0.0
|
|
|
+ }
|
|
|
+ return sumSquares
|
|
|
+}
|
|
|
+
|
|
|
+func (self *LibratoReporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot *librato.MetricsFormat, err error) {
|
|
|
+ snapshot = &librato.MetricsFormat{}
|
|
|
+ snapshot.MeasureTime = now.Unix()
|
|
|
+ snapshot.Source = self.Source
|
|
|
+ snapshot.Gauges = make([]interface{}, 0)
|
|
|
+ snapshot.Counters = make([]librato.Metric, 0)
|
|
|
+ histogramGaugeCount := 1 + len(self.Percentiles)
|
|
|
+ r.Each(func(name string, metric interface{}) {
|
|
|
+ switch m := metric.(type) {
|
|
|
+ case metrics.Counter:
|
|
|
+ libratoName := fmt.Sprintf("%s.%s", name, "count")
|
|
|
+ snapshot.Counters = append(snapshot.Counters, librato.Metric{Name: libratoName, Value: float64(m.Count())})
|
|
|
+ case metrics.Gauge:
|
|
|
+ snapshot.Gauges = append(snapshot.Gauges, librato.Metric{Name: name, Value: float64(m.Value())})
|
|
|
+ case metrics.Histogram:
|
|
|
+ if m.Count() > 0 {
|
|
|
+ libratoName := fmt.Sprintf("%s.%s", name, "hist")
|
|
|
+ gauges := make([]interface{}, histogramGaugeCount, histogramGaugeCount)
|
|
|
+ gauges[0] = librato.Gauge{
|
|
|
+ Name: libratoName,
|
|
|
+ Count: uint64(m.Count()),
|
|
|
+ Sum: m.Mean() * float64(m.Count()),
|
|
|
+ Max: float64(m.Max()),
|
|
|
+ Min: float64(m.Min()),
|
|
|
+ SumSquares: sumSquares(m),
|
|
|
+ }
|
|
|
+ for i, p := range self.Percentiles {
|
|
|
+ gauges[i+1] = librato.Metric{Name: fmt.Sprintf("%s.%.2f", libratoName, p), Value: m.Percentile(p)}
|
|
|
+ }
|
|
|
+ snapshot.Gauges = append(snapshot.Gauges, gauges...)
|
|
|
+ }
|
|
|
+ case metrics.Meter:
|
|
|
+ snapshot.Counters = append(snapshot.Counters, librato.Metric{Name: name, Value: float64(m.Count())})
|
|
|
+ snapshot.Gauges = append(snapshot.Gauges,
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "1min"),
|
|
|
+ Value: m.Rate1(),
|
|
|
+ },
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "5min"),
|
|
|
+ Value: m.Rate5(),
|
|
|
+ },
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "15min"),
|
|
|
+ Value: m.Rate15(),
|
|
|
+ },
|
|
|
+ )
|
|
|
+ case metrics.Timer:
|
|
|
+ if m.Count() > 0 {
|
|
|
+ libratoName := fmt.Sprintf("%s.%s", name, "timer")
|
|
|
+ gauges := make([]interface{}, histogramGaugeCount, histogramGaugeCount)
|
|
|
+ gauges[0] = librato.Gauge{
|
|
|
+ Name: libratoName,
|
|
|
+ Count: uint64(m.Count()),
|
|
|
+ Sum: m.Mean() * float64(m.Count()),
|
|
|
+ Max: float64(m.Max()),
|
|
|
+ Min: float64(m.Min()),
|
|
|
+ SumSquares: sumSquaresTimer(m),
|
|
|
+ }
|
|
|
+ for i, p := range self.Percentiles {
|
|
|
+ gauges[i+1] = librato.Metric{Name: fmt.Sprintf("%s.%2.0f", libratoName, p*100), Value: m.Percentile(p)}
|
|
|
+ }
|
|
|
+ snapshot.Gauges = append(snapshot.Gauges, gauges...)
|
|
|
+ snapshot.Gauges = append(snapshot.Gauges,
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "1min"),
|
|
|
+ Value: m.Rate1(),
|
|
|
+ },
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "5min"),
|
|
|
+ Value: m.Rate5(),
|
|
|
+ },
|
|
|
+ librato.Metric{
|
|
|
+ Name: fmt.Sprintf("%s.%s", name, "15min"),
|
|
|
+ Value: m.Rate15(),
|
|
|
+ },
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return
|
|
|
+}
|