github.com/go-graphite/carbonapi@v0.17.0/expr/functions/keepLastValue/function.go (about) 1 package keepLastValue 2 3 import ( 4 "context" 5 "math" 6 "strconv" 7 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 keepLastValue 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 := &keepLastValue{} 23 functions := []string{"keepLastValue"} 24 for _, n := range functions { 25 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 26 } 27 return res 28 } 29 30 // keepLastValue(seriesList, limit=inf) 31 func (f *keepLastValue) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 32 33 arg, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 34 if err != nil { 35 return nil, err 36 } 37 38 var keep parser.IntOrInf 39 var keepStr string 40 41 keep, err = e.GetIntOrInfNamedOrPosArgDefault("limit", 1, parser.IntOrInf{IsInf: true}) 42 if err != nil { 43 return nil, err 44 } 45 46 if !keep.IsInf { 47 keepStr = strconv.Itoa(keep.IntVal) 48 } else { 49 keepStr = "inf" 50 } 51 52 var results []*types.MetricData 53 54 for _, a := range arg { 55 var name string 56 if e.ArgsLen() < 2 { 57 name = "keepLastValue(" + a.Name + ")" 58 } else { 59 name = "keepLastValue(" + a.Name + "," + keepStr + ")" 60 } 61 62 r := a.CopyLinkTags() 63 r.Name = name 64 r.Values = make([]float64, len(a.Values)) 65 66 prev := math.NaN() 67 missing := 0 68 69 for i, v := range a.Values { 70 if math.IsNaN(v) { 71 72 if (keep.IsInf || keep.IntVal < 0 || missing < keep.IntVal) && !math.IsNaN(prev) { 73 r.Values[i] = prev 74 missing++ 75 } else { 76 r.Values[i] = math.NaN() 77 } 78 79 continue 80 } 81 missing = 0 82 prev = v 83 r.Values[i] = v 84 } 85 results = append(results, r) 86 } 87 return results, err 88 } 89 90 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 91 func (f *keepLastValue) Description() map[string]types.FunctionDescription { 92 return map[string]types.FunctionDescription{ 93 "keepLastValue": { 94 Description: "Takes one metric or a wildcard seriesList, and optionally a limit to the number of 'None' values to skip over.\nContinues the line with the last received value when gaps ('None' values) appear in your data, rather than breaking your line.\n\nExample:\n\n.. code-block:: none\n\n &target=keepLastValue(Server01.connections.handled)\n &target=keepLastValue(Server01.connections.handled, 10)", 95 Function: "keepLastValue(seriesList, limit=inf)", 96 Group: "Transform", 97 Module: "graphite.render.functions", 98 Name: "keepLastValue", 99 Params: []types.FunctionParam{ 100 { 101 Name: "seriesList", 102 Required: true, 103 Type: types.SeriesList, 104 }, 105 { 106 Default: types.NewSuggestion(math.Inf(1)), 107 Name: "limit", 108 Type: types.IntOrInf, 109 }, 110 }, 111 SeriesChange: true, // function aggregate metrics or change series items count 112 NameChange: true, // name changed 113 ValuesChange: true, // values changed 114 }, 115 } 116 }