From a7a48d3593f414581cd87275c70031be88e3daa4 Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Wed, 17 Feb 2016 10:08:56 -0500 Subject: [PATCH] cmd/bosun: Add linelr func for visualizing a linear regression line --- cmd/bosun/expr/funcs.go | 42 +++++++++++++++++++++++++++++++++++++++++ docs/expressions.md | 12 ++++++++++++ 2 files changed, 54 insertions(+) diff --git a/cmd/bosun/expr/funcs.go b/cmd/bosun/expr/funcs.go index 43ae37fde7..89d0a0af6a 100644 --- a/cmd/bosun/expr/funcs.go +++ b/cmd/bosun/expr/funcs.go @@ -178,6 +178,12 @@ var builtins = map[string]parse.Func{ Tags: tagFirst, F: Forecast_lr, }, + "linelr": { + Args: []models.FuncType{models.TypeSeriesSet, models.TypeString}, + Return: models.TypeSeriesSet, + Tags: tagFirst, + F: Line_lr, + }, "last": { Args: []models.FuncType{models.TypeSeriesSet}, Return: models.TypeNumberSet, @@ -1331,6 +1337,42 @@ func (e *State) forecast_lr(dps Series, args ...float64) float64 { return s.Seconds() } +func Line_lr(e *State, T miniprofiler.Timer, series *Results, d string) (*Results, error) { + dur, err := opentsdb.ParseDuration(d) + if err != nil { + return series, err + } + for _, res := range series.Results { + res.Value = line_lr(res.Value.(Series), time.Duration(dur)) + res.Group.Merge(opentsdb.TagSet{"regression": "line"}) + } + return series, nil +} + +// line_lr generates a series representing the line up to duration in the future. +func line_lr(dps Series, d time.Duration) Series { + var x []float64 + var y []float64 + sortedDPS := NewSortedSeries(dps) + var maxT time.Time + if len(sortedDPS) > 1 { + maxT = sortedDPS[len(sortedDPS)-1].T + } + for _, v := range sortedDPS { + xv := float64(v.T.Unix()) + x = append(x, xv) + y = append(y, v.V) + } + var slope, intercept, _, _, _, _ = stats.LinearRegression(x, y) + s := make(Series) + // First point in the regression line + s[maxT] = float64(maxT.Unix())*slope + intercept + // Last point + last := maxT.Add(d) + s[last] = float64(last.Unix())*slope + intercept + return s +} + func Percentile(e *State, T miniprofiler.Timer, series *Results, p *Results) (r *Results, err error) { return reduce(e, T, series, percentile, p) } diff --git a/docs/expressions.md b/docs/expressions.md index c5e90f1c7f..c5ec718ee6 100644 --- a/docs/expressions.md +++ b/docs/expressions.md @@ -311,6 +311,18 @@ Returns the first (least recent) data point in each series. Returns the number of seconds until a linear regression of each series will reach y_val. +## linelr(seriesSet, d Duration) seriesSet + +Linelr return the linear regression line from the end of each series to end+duration (an [OpenTSDB duration string](http://opentsdb.net/docs/build/html/user_guide/query/dates.html)). It adds `regression=line` to the group / tagset. It is meant for graphing with expressions, for example: + +``` +$d = "1w" +$q = q("avg:1h-avg:os.disk.fs.percent_free{}{host=ny-tsdb*,disk=/mnt*}", "2w", "") +$line = linelr($q, "3n") +$m = merge($q, $line) +$m +``` + ## last(seriesSet) numberSet Returns the last (most recent) data point in each series.