-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ali Alrahahleh
committed
Jun 28, 2016
1 parent
06cb5a0
commit 3008ce0
Showing
9 changed files
with
318 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package telegraf | ||
|
||
type Filter interface { | ||
// SampleConfig returns the default configuration of the Input | ||
SampleConfig() string | ||
|
||
// Description returns a one-sentence description on the Input | ||
Description() string | ||
|
||
//create pipe for filter | ||
Pipe(in chan Metric) chan Metric | ||
|
||
// start the filter | ||
Start(shutdown chan struct{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package all | ||
|
||
import ( | ||
_ "github.com/influxdata/telegraf/plugins/filters/histogram" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package histogram | ||
|
||
import ( | ||
"github.com/VividCortex/gohistogram" | ||
"math" | ||
) | ||
|
||
type Aggregate struct { | ||
hist *gohistogram.NumericHistogram | ||
sum float64 | ||
max float64 | ||
min float64 | ||
} | ||
|
||
func (a *Aggregate) Add(n float64) { | ||
a.sum += n | ||
if a.max < n { | ||
a.max = n | ||
} | ||
if a.min > n { | ||
a.min = n | ||
} | ||
a.hist.Add(n) | ||
} | ||
|
||
func (a *Aggregate) Quantile(q float64) float64 { | ||
return a.hist.Quantile(q) | ||
} | ||
|
||
func (a *Aggregate) Sum() float64 { | ||
return a.sum | ||
} | ||
|
||
func (a *Aggregate) CDF(x float64) float64 { | ||
return a.hist.CDF(x) | ||
} | ||
|
||
func (a *Aggregate) Mean() float64 { | ||
return a.hist.Mean() | ||
} | ||
|
||
func (a *Aggregate) Variance() float64 { | ||
return a.hist.Variance() | ||
} | ||
|
||
func (a *Aggregate) Count() float64 { | ||
return a.hist.Count() | ||
} | ||
|
||
func (a *Aggregate) Max() float64 { | ||
return a.max | ||
} | ||
|
||
func (a *Aggregate) Min() float64 { | ||
return a.min | ||
} | ||
|
||
func NewAggregate(n int) *Aggregate { | ||
return &Aggregate{ | ||
hist: gohistogram.NewHistogram(n), | ||
max: math.SmallestNonzeroFloat64, | ||
min: math.MaxFloat64, | ||
sum: 0, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package histogram | ||
|
||
import ( | ||
"crypto/sha1" | ||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/filters" | ||
"io" | ||
"log" | ||
"strconv" | ||
"time" | ||
) | ||
|
||
type metricID struct { | ||
Name string | ||
TagHash [sha1.Size]byte | ||
} | ||
type Histogram struct { | ||
inch chan telegraf.Metric | ||
outch chan telegraf.Metric | ||
FlushInterval string | ||
interval time.Duration | ||
Bucketsize int | ||
Metrics map[string][]float64 | ||
fieldMap map[metricID]map[string]*Aggregate | ||
metricTags map[metricID]map[string]string | ||
} | ||
|
||
func (h *Histogram) Description() string { | ||
return "Histogram: read metrics from inputs and create histogram for output" | ||
} | ||
|
||
func (h *Histogram) SampleConfig() string { | ||
return ` | ||
## Histogram Filter | ||
## This filter can be used to generate | ||
## (mean varince percentile count) | ||
## values generated are approxmation please refer to | ||
## Ben-Haim & Yom-Tov's A Streaming Parallel Decision Tree Algorithm | ||
## http://jmlr.org/papers/volume11/ben-haim10a/ben-haim10a.pdf | ||
##[[filter.histogram]] | ||
## bucket size if increase it will increase accuracy | ||
## but it will increase memory usage | ||
## bucketsize = 20 | ||
## [filter.histogram.metrics] | ||
## if array is empty only count mean | ||
## and variance will be cacluated. _ALL_METRIC special constanct | ||
## can be used instead of metric name this will aggregate all the | ||
## the merrtics for this filer | ||
## metric name = [percentiles] | ||
## tail = [0.90] | ||
` | ||
} | ||
|
||
func (h *Histogram) Pipe(in chan telegraf.Metric) chan telegraf.Metric { | ||
h.inch = in | ||
h.outch = make(chan telegraf.Metric, 10000) | ||
return h.outch | ||
} | ||
|
||
func (h *Histogram) Start(shutdown chan struct{}) { | ||
interval, _ := time.ParseDuration(h.FlushInterval) | ||
ticker := time.NewTicker(interval) | ||
for { | ||
select { | ||
case m := <-h.inch: | ||
if h.IsEnabled(m.Name()) { | ||
h.AddMetric(m) | ||
} else { | ||
h.outch <- m | ||
} | ||
case <-shutdown: | ||
log.Printf("Shuting down filters, All metric in the queue will be lost.") | ||
return | ||
case <-ticker.C: | ||
h.OutputMetric() | ||
} | ||
} | ||
} | ||
|
||
func (h *Histogram) hashTags(m map[string]string) (result [sha1.Size]byte) { | ||
hash := sha1.New() | ||
io.WriteString(hash, "tags:") | ||
for key, _ := range m { | ||
io.WriteString(hash, key) | ||
} | ||
copy(result[:], hash.Sum(nil)) | ||
return result | ||
} | ||
|
||
func (h *Histogram) AddMetric(metric telegraf.Metric) { | ||
mID := metricID{ | ||
Name: metric.Name(), | ||
TagHash: h.hashTags(metric.Tags()), | ||
} | ||
if h.fieldMap[mID] == nil { | ||
h.fieldMap[mID] = make(map[string]*Aggregate) | ||
} | ||
if h.metricTags[mID] == nil { | ||
h.metricTags[mID] = make(map[string]string) | ||
} | ||
h.metricTags[mID] = metric.Tags() | ||
for key, val := range metric.Fields() { | ||
switch v := val.(type) { | ||
case float64: | ||
if h.fieldMap[mID][key] == nil { | ||
h.fieldMap[mID][key] = NewAggregate(h.Bucketsize) | ||
} | ||
hist := h.fieldMap[mID][key] | ||
hist.Add(v) | ||
default: | ||
log.Printf("When stats enabled all the fields should be of type float64 [field name %s]", key) | ||
} | ||
} | ||
} | ||
|
||
func (h *Histogram) IsEnabled(name string) bool { | ||
_, isAllEnabled := h.Metrics["_ALL_METRIC"] | ||
_, ok := h.Metrics[name] | ||
return ok || isAllEnabled | ||
} | ||
|
||
func (h *Histogram) OutputMetric() { | ||
for mID, fields := range h.fieldMap { | ||
mFields := make(map[string]interface{}) | ||
for key, val := range fields { | ||
for _, perc := range h.Metrics[mID.Name] { | ||
p := strconv.FormatFloat(perc*100, 'f', 0, 64) | ||
mFields[key+"_p"+p] = val.Quantile(perc) | ||
} | ||
mFields[key+"_variance"] = val.Variance() | ||
mFields[key+"_mean"] = val.Mean() | ||
mFields[key+"_count"] = val.Count() | ||
mFields[key+"_sum"] = val.Sum() | ||
mFields[key+"_max"] = val.Max() | ||
mFields[key+"_min"] = val.Min() | ||
} | ||
metric, _ := telegraf.NewMetric(mID.Name, h.metricTags[mID], mFields, time.Now().UTC()) | ||
h.outch <- metric | ||
delete(h.fieldMap, mID) | ||
delete(h.metricTags, mID) | ||
} | ||
} | ||
|
||
func (h *Histogram) Reset() { | ||
h.fieldMap = make(map[metricID]map[string]*Aggregate) | ||
h.metricTags = make(map[metricID]map[string]string) | ||
} | ||
|
||
func init() { | ||
filters.Add("histogram", func() telegraf.Filter { | ||
return &Histogram{ | ||
fieldMap: make(map[metricID]map[string]*Aggregate), | ||
metricTags: make(map[metricID]map[string]string), | ||
} | ||
}) | ||
} |
Oops, something went wrong.