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  }