diff --git a/structs.go b/structs.go index df78bbd..fae2e16 100644 --- a/structs.go +++ b/structs.go @@ -5,6 +5,7 @@ import ( "errors" "launchpad.net/goamz/s3" "log" + "sort" "strconv" "time" ) @@ -85,6 +86,74 @@ func newDashboardMetric() *dashboardMetric { } } +func median(values []float64) float64 { + sort.Float64s(values) + + // If even, take an average + if len(values)%2 == 0 { + return 0.5*values[len(values)/2] + 0.5*values[len(values)/2-1] + } + return values[len(values)/2-1] +} + +func absoluteValue(value float64) float64 { + if value < 0 { + value = -value + } + return value +} + +func absoluteDeviation(values []float64) []float64 { + medianValue := median(values) + + deviation := make([]float64, len(values)) + + for i, _ := range values { + deviation[i] = absoluteValue(values[i] - medianValue) + } + + return deviation +} + +func (dm *dashboardMetric) getValueArray() []float64 { + values := make([]float64, 0) + + for _, v := range dm.HistoricalData { + values = append(values, v.Value) + } + + return values +} + +func (dm *dashboardMetric) Median() float64 { + return median(dm.getValueArray()) +} + +func (dm *dashboardMetric) MedianAbsoluteDeviation() (float64, float64) { + values := dm.getValueArray() + medianValue := dm.Median() + + return medianValue, median(absoluteDeviation(values)) +} + +func (dm *dashboardMetric) MadMultiplier() float64 { + medianValue, MAD := dm.MedianAbsoluteDeviation() + + return absoluteValue(dm.Value-medianValue) / MAD +} + +func (dm *dashboardMetric) StatisticalStatus() string { + mult := dm.MadMultiplier() + + if mult > 4 { + return "Critical" + } else if mult > 3 { + return "Warning" + } + + return "OK" +} + func (dm *dashboardMetric) LabelHistory() string { s := "[" for i, v := range dm.HistoricalData { diff --git a/templates/dashboard.html b/templates/dashboard.html index 90414e5..50c84a4 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -81,11 +81,11 @@ {% else %} {% for metric in metrics %} - {% if metric.Status == "OK" %} + {% if metric.StatisticalStatus == "OK" %}
- {% elif metric.Status == "Warning" %} + {% elif metric.StatisticalStatus == "Warning" %}
- {% elif metric.Status == "Critical" %} + {% elif metric.StatisticalStatus == "Critical" %}
{% else %}
@@ -93,7 +93,7 @@

{{ metric.Title }}

{{ metric.Description }}

- Current Value: {{ metric.Value }} + Current Value: {{ metric.Value }} {{ metric.MadMultiplier }} MAD above the Median ({{ metric.Median }})