func graphite(c *GraphiteConfig) error { now := time.Now().Unix() du := float64(c.DurationUnit) conn, err := net.DialTCP("tcp", nil, c.Addr) if nil != err { return err } defer conn.Close() w := bufio.NewWriter(conn) c.Registry.Each(func(name string, i interface{}) { k := c.Prefix + name switch metric := i.(type) { case Counter: fmt.Fprintf(w, "%s %d %d\n", m2.Counter(k, ""), metric.Count(), now) case Gauge: fmt.Fprintf(w, "%s %d %d\n", m2.Gauge(k, ""), metric.Value(), now) case GaugeFloat64: fmt.Fprintf(w, "%s %f %d\n", m2.Gauge(k, ""), metric.Value(), now) case Histogram: h := metric.Snapshot() ps := h.Percentiles(c.Percentiles) fmt.Fprintf(w, "%s %d %d\n", m2.CountMetric(k, ""), h.Count(), now) fmt.Fprintf(w, "%s %d %d\n", m2.Min(k, "", "", ""), h.Min(), now) fmt.Fprintf(w, "%s %d %d\n", m2.Max(k, "", "", ""), h.Max(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "", "", ""), h.Mean(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Std(k, "", "", ""), h.StdDev(), now) for psIdx, psKey := range c.Percentiles { pct := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) fmt.Fprintf(w, "%s %.2f %d\n", m2.Max(k, "", pct, ""), ps[psIdx], now) } case Meter: m := metric.Snapshot() fmt.Fprintf(w, "%s %d %d\n", m2.CountMetric(k, ""), m.Count(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "1m", "", "60"), m.Rate1(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "5m", "", "300"), m.Rate5(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "15m", "", "900"), m.Rate15(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "start", "", "start"), m.RateMean(), now) case Timer: t := metric.Snapshot() ps := t.Percentiles(c.Percentiles) fmt.Fprintf(w, "%s %d %d\n", m2.CountMetric(k, ""), t.Count(), now) fmt.Fprintf(w, "%s %d %d\n", m2.Min(k, "", "", ""), t.Min()/int64(du), now) fmt.Fprintf(w, "%s %d %d\n", m2.Max(k, "", "", ""), t.Max()/int64(du), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "", "", ""), t.Mean()/du, now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Std(k, "", "", ""), t.StdDev()/du, now) for psIdx, psKey := range c.Percentiles { pct := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) fmt.Fprintf(w, "%s %.2f %d\n", m2.Max(k, "", pct, ""), ps[psIdx], now) } fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "1m", "", "60"), t.Rate1(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "5m", "", "300"), t.Rate5(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "15m", "", "900"), t.Rate15(), now) fmt.Fprintf(w, "%s %.2f %d\n", m2.Mean(k, "start", "", "start"), t.RateMean(), now) } w.Flush() }) return nil }
// Process computes the outbound metrics for timers and puts them in the buffer func (timers *Timers) Process(buf []byte, now int64, interval int) ([]byte, int64) { // these are the metrics that get exposed: // count estimate of original amount of metrics sent, by dividing received by samplerate // count_ps same but per second // lower // mean // arithmetic mean // mean_<pct> // arithmetic mean of values below <pct> percentile // median // std standard deviation // sum // sum_90 // upper // upper_90 / lower_90 var num int64 for u, t := range timers.Values { if len(t.Points) > 0 { seen := len(t.Points) count := t.Amount_submitted count_ps := float64(count) / float64(interval) num++ sort.Sort(t.Points) min := t.Points[0] max := t.Points[seen-1] sum := float64(0) for _, value := range t.Points { sum += value } mean := float64(sum) / float64(seen) sumOfDiffs := float64(0) for _, value := range t.Points { sumOfDiffs += math.Pow((float64(value) - mean), 2) } stddev := math.Sqrt(sumOfDiffs / float64(seen)) mid := seen / 2 var median float64 if seen%2 == 1 { median = t.Points[mid] } else { median = (t.Points[mid-1] + t.Points[mid]) / 2 } var cumulativeValues Float64Slice cumulativeValues = make(Float64Slice, seen, seen) cumulativeValues[0] = t.Points[0] for i := 1; i < seen; i++ { cumulativeValues[i] = t.Points[i] + cumulativeValues[i-1] } maxAtThreshold := max sum_pct := sum mean_pct := mean for _, pct := range timers.pctls { if seen > 1 { var abs float64 if pct.float >= 0 { abs = pct.float } else { abs = 100 + pct.float } // poor man's math.Round(x): // math.Floor(x + 0.5) indexOfPerc := int(math.Floor(((abs / 100.0) * float64(seen)) + 0.5)) if pct.float >= 0 { sum_pct = cumulativeValues[indexOfPerc-1] maxAtThreshold = t.Points[indexOfPerc-1] } else { maxAtThreshold = t.Points[indexOfPerc] sum_pct = cumulativeValues[seen-1] - cumulativeValues[seen-indexOfPerc-1] } mean_pct = float64(sum_pct) / float64(indexOfPerc) } var pctstr string var fn func(metric_in, prefix, percentile, timespec string) string if pct.float >= 0 { pctstr = pct.str fn = m20.Max } else { pctstr = pct.str[1:] fn = m20.Min } buf = common.WriteFloat64(buf, []byte(fn(u, timers.prefix, pctstr, "")), maxAtThreshold, now) buf = common.WriteFloat64(buf, []byte(m20.Mean(u, timers.prefix, pctstr, "")), mean_pct, now) buf = common.WriteFloat64(buf, []byte(m20.Sum(u, timers.prefix, pctstr, "")), sum_pct, now) } buf = common.WriteFloat64(buf, []byte(m20.Mean(u, timers.prefix, "", "")), mean, now) buf = common.WriteFloat64(buf, []byte(m20.Median(u, timers.prefix, "", "")), median, now) buf = common.WriteFloat64(buf, []byte(m20.Std(u, timers.prefix, "", "")), stddev, now) buf = common.WriteFloat64(buf, []byte(m20.Sum(u, timers.prefix, "", "")), sum, now) buf = common.WriteFloat64(buf, []byte(m20.Max(u, timers.prefix, "", "")), max, now) buf = common.WriteFloat64(buf, []byte(m20.Min(u, timers.prefix, "", "")), min, now) buf = common.WriteInt64(buf, []byte(m20.CountPckt(u, timers.prefix)), count, now) buf = common.WriteFloat64(buf, []byte(m20.RatePckt(u, timers.prefix)), count_ps, now) } } return buf, num }