github.com/go-graphite/carbonapi@v0.17.0/expr/functions/compressPeriodicGaps/function.go (about) 1 package compressPeriodicGaps 2 3 import ( 4 "context" 5 "math" 6 7 "github.com/go-graphite/carbonapi/expr/consolidations" 8 "github.com/go-graphite/carbonapi/expr/helper" 9 "github.com/go-graphite/carbonapi/expr/interfaces" 10 "github.com/go-graphite/carbonapi/expr/types" 11 "github.com/go-graphite/carbonapi/pkg/parser" 12 ) 13 14 type compressPeriodicGaps struct{} 15 16 func GetOrder() interfaces.Order { 17 return interfaces.Any 18 } 19 20 func New(configFile string) []interfaces.FunctionMetadata { 21 res := make([]interfaces.FunctionMetadata, 0) 22 f := &compressPeriodicGaps{} 23 functions := []string{"compressPeriodicGaps"} 24 for _, n := range functions { 25 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 26 } 27 return res 28 } 29 30 // compressPeriodicGaps(seriesList) 31 func (f *compressPeriodicGaps) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 32 args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 33 if err != nil { 34 return nil, err 35 } 36 var results []*types.MetricData 37 38 for _, a := range args { 39 firstSeen := -1 40 secondSeen := -1 41 interval := math.NaN() 42 name := "compressPeriodicGaps(" + a.Name + ")" 43 44 for i, v := range a.Values { 45 if !math.IsNaN(v) { 46 if firstSeen >= 0 { 47 secondSeen = i 48 break 49 } else { 50 firstSeen = i 51 } 52 } 53 } 54 stepGuess := secondSeen - firstSeen 55 thirdSeen := secondSeen + stepGuess 56 if stepGuess > 1 && thirdSeen <= len(a.Values)-2 { 57 if !math.IsNaN(a.Values[thirdSeen]) { 58 if math.IsNaN(a.Values[thirdSeen-1]) && math.IsNaN(a.Values[thirdSeen+1]) { 59 interval = float64(int64(stepGuess) * a.StepTime) 60 } 61 } 62 } 63 64 if math.IsNaN(interval) { 65 r := a.CopyLink() 66 r.Name = name 67 results = append(results, r) 68 } else { 69 newStart := a.StartTime + int64(firstSeen)*a.StepTime 70 newValues := make([]float64, 0, int64(interval)/a.StepTime) 71 ridx := 0 72 intervalItems := 0 73 intervalEnd := float64(newStart) + interval 74 t := a.StartTime // unadjusted 75 buckets := helper.GetBuckets(newStart, a.StopTime, int64(interval)) 76 77 r := a.CopyLink() 78 r.Name = name 79 r.StepTime = int64(interval) 80 r.StartTime = newStart 81 r.Values = make([]float64, buckets) 82 83 for _, v := range a.Values { 84 intervalItems++ 85 if !math.IsNaN(v) { 86 newValues = append(newValues, v) 87 } 88 89 t += a.StepTime 90 91 if t >= a.StopTime { 92 break 93 } 94 95 if t >= int64(intervalEnd) { 96 rv := consolidations.SummarizeValues("last", newValues, a.XFilesFactor) 97 98 r.Values[ridx] = rv 99 ridx++ 100 intervalEnd += interval 101 intervalItems = 0 102 newValues = newValues[:0] 103 } 104 } 105 106 // last partial bucket 107 if intervalItems > 0 { 108 rv := consolidations.SummarizeValues("last", newValues, a.XFilesFactor) 109 r.Values[ridx] = rv 110 } 111 112 r.StopTime = r.StartTime + int64(len(r.Values))*r.StepTime 113 results = append(results, r) 114 } 115 116 } 117 118 return results, nil 119 } 120 121 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 122 func (f *compressPeriodicGaps) Description() map[string]types.FunctionDescription { 123 return map[string]types.FunctionDescription{ 124 "compressPeriodicGaps": { 125 Description: "Tries to intelligently remove periodic None’s from series, recalculating start, stop and step values.\n You can use summarize(seriesList, ‘<desired step>’, ‘last’) function for that also, but this function trying to guess desired step automatically.\n Can be used in case of fix metric with improper resolution. Especially useful for derivative functions, which are not working with series with regular gaps.\n\n.. code-block:: none\n\n &target=compressPeriodicGaps(Server.instance01.threads.busy)\n\n", 126 Function: "compressPeriodicGaps(seriesList)", 127 Group: "Transform", 128 Module: "graphite.render.functions", 129 Name: "compressPeriodicGaps", 130 Params: []types.FunctionParam{ 131 { 132 Name: "seriesList", 133 Required: true, 134 Type: types.SeriesList, 135 }, 136 }, 137 }, 138 } 139 }