From 43e9527a0fe93e4ffa627f2ebbe570ca896c0356 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 27 May 2021 14:16:10 +0300 Subject: [PATCH] Implement timeShift --- pkg/datasource/functions.go | 77 +++++++++++++++++++++++++++ pkg/datasource/zabbix.go | 5 ++ pkg/timeseries/transform_functions.go | 14 +++++ 3 files changed, 96 insertions(+) diff --git a/pkg/datasource/functions.go b/pkg/datasource/functions.go index f95c758..6e00539 100644 --- a/pkg/datasource/functions.go +++ b/pkg/datasource/functions.go @@ -3,9 +3,11 @@ package datasource import ( "fmt" "strconv" + "strings" "github.com/alexanderzobnin/grafana-zabbix/pkg/gtime" "github.com/alexanderzobnin/grafana-zabbix/pkg/timeseries" + "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix" ) const RANGE_VARIABLE_VALUE = "range_series" @@ -41,12 +43,16 @@ type DataProcessingFunc = func(series timeseries.TimeSeries, params ...interface type AggDataProcessingFunc = func(series []*timeseries.TimeSeriesData, params ...interface{}) ([]*timeseries.TimeSeriesData, error) +type PreProcessingFunc = func(query *QueryModel, items []*zabbix.Item, params ...interface{}) error + var seriesFuncMap map[string]DataProcessingFunc var aggFuncMap map[string]AggDataProcessingFunc var filterFuncMap map[string]AggDataProcessingFunc +var timeFuncMap map[string]PreProcessingFunc + var frontendFuncMap map[string]bool func init() { @@ -55,6 +61,7 @@ func init() { "scale": applyScale, "offset": applyOffset, "percentile": applyPercentile, + "timeShift": applyTimeShiftPost, } aggFuncMap = map[string]AggDataProcessingFunc{ @@ -69,6 +76,10 @@ func init() { "sortSeries": applySortSeries, } + timeFuncMap = map[string]PreProcessingFunc{ + "timeShift": applyTimeShiftPre, + } + // Functions processing on the frontend frontendFuncMap = map[string]bool{ "setAlias": true, @@ -109,6 +120,20 @@ func applyFunctions(series []*timeseries.TimeSeriesData, functions []QueryFuncti return series, nil } +// applyFunctionsPre applies functions requires pre-processing, like timeShift() (it needs to change original time range) +func applyFunctionsPre(query *QueryModel, items []*zabbix.Item) error { + for _, f := range query.Functions { + if applyFunc, ok := timeFuncMap[f.Def.Name]; ok { + err := applyFunc(query, items, f.Params...) + if err != nil { + return err + } + } + } + + return nil +} + func applyGroupBy(series timeseries.TimeSeries, params ...interface{}) (timeseries.TimeSeries, error) { pInterval, err := MustString(params[0]) pAgg, err := MustString(params[1]) @@ -256,6 +281,58 @@ func applySortSeries(series []*timeseries.TimeSeriesData, params ...interface{}) return sorted, nil } +func applyTimeShiftPre(query *QueryModel, items []*zabbix.Item, params ...interface{}) error { + pInterval, err := MustString(params[0]) + if err != nil { + return errParsingFunctionParam(err) + } + shiftForward := false + pInterval = strings.TrimPrefix(pInterval, "-") + if strings.Index(pInterval, "+") == 0 { + pInterval = strings.TrimPrefix(pInterval, "+") + shiftForward = true + } + + interval, err := gtime.ParseInterval(pInterval) + if err != nil { + return errParsingFunctionParam(err) + } + + if shiftForward { + query.TimeRange.From = query.TimeRange.From.Add(interval) + query.TimeRange.To = query.TimeRange.To.Add(interval) + } else { + query.TimeRange.From = query.TimeRange.From.Add(-interval) + query.TimeRange.To = query.TimeRange.To.Add(-interval) + } + + return nil +} + +func applyTimeShiftPost(series timeseries.TimeSeries, params ...interface{}) (timeseries.TimeSeries, error) { + pInterval, err := MustString(params[0]) + if err != nil { + return nil, errParsingFunctionParam(err) + } + shiftForward := false + pInterval = strings.TrimPrefix(pInterval, "-") + if strings.Index(pInterval, "+") == 0 { + pInterval = strings.TrimPrefix(pInterval, "+") + shiftForward = true + } + + interval, err := gtime.ParseInterval(pInterval) + if err != nil { + return nil, errParsingFunctionParam(err) + } + if shiftForward == true { + interval = -interval + } + + transformFunc := timeseries.TransformShiftTime(interval) + return series.Transform(transformFunc), nil +} + func getAggFunc(agg string) timeseries.AggFunc { switch agg { case "avg": diff --git a/pkg/datasource/zabbix.go b/pkg/datasource/zabbix.go index d692d51..c761b30 100644 --- a/pkg/datasource/zabbix.go +++ b/pkg/datasource/zabbix.go @@ -68,6 +68,11 @@ func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context consolidateBy = valueType } + err := applyFunctionsPre(query, items) + if err != nil { + return nil, err + } + history, err := ds.getHistotyOrTrend(ctx, query, items, valueType) if err != nil { return nil, err diff --git a/pkg/timeseries/transform_functions.go b/pkg/timeseries/transform_functions.go index 6e95d0f..d989b95 100644 --- a/pkg/timeseries/transform_functions.go +++ b/pkg/timeseries/transform_functions.go @@ -1,5 +1,7 @@ package timeseries +import "time" + func TransformScale(factor float64) TransformFunc { return func(point TimePoint) TimePoint { return transformScale(point, factor) @@ -12,6 +14,12 @@ func TransformOffset(offset float64) TransformFunc { } } +func TransformShiftTime(interval time.Duration) TransformFunc { + return func(point TimePoint) TimePoint { + return transformShiftTime(point, interval) + } +} + func transformScale(point TimePoint, factor float64) TimePoint { if point.Value != nil { newValue := *point.Value * factor @@ -27,3 +35,9 @@ func transformOffset(point TimePoint, offset float64) TimePoint { } return point } + +func transformShiftTime(point TimePoint, interval time.Duration) TimePoint { + shiftedTime := point.Time.Add(interval) + point.Time = shiftedTime + return point +}