github.com/go-graphite/carbonapi@v0.17.0/expr/functions/transformNull/function.go (about) 1 package transformNull 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "strconv" 8 9 pbv3 "github.com/go-graphite/protocol/carbonapi_v3_pb" 10 11 "github.com/go-graphite/carbonapi/expr/helper" 12 "github.com/go-graphite/carbonapi/expr/interfaces" 13 "github.com/go-graphite/carbonapi/expr/tags" 14 "github.com/go-graphite/carbonapi/expr/types" 15 "github.com/go-graphite/carbonapi/pkg/parser" 16 ) 17 18 type transformNull struct{} 19 20 func GetOrder() interfaces.Order { 21 return interfaces.Any 22 } 23 24 func New(configFile string) []interfaces.FunctionMetadata { 25 res := make([]interfaces.FunctionMetadata, 0) 26 f := &transformNull{} 27 functions := []string{"transformNull"} 28 for _, n := range functions { 29 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 30 } 31 return res 32 } 33 34 // transformNull(seriesList, default=0) 35 func (f *transformNull) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 36 arg, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 37 if err != nil { 38 return nil, err 39 } 40 defv, err := e.GetFloatNamedOrPosArgDefault("default", 1, 0) 41 if err != nil { 42 return nil, err 43 } 44 defaultOnAbsent, err := e.GetBoolNamedOrPosArgDefault("defaultOnAbsent", 3, false) 45 if err != nil { 46 return nil, err 47 } 48 49 _, ok := e.NamedArg("default") 50 if !ok { 51 ok = e.ArgsLen() > 1 52 } 53 defvStr := strconv.FormatFloat(defv, 'g', -1, 64) 54 55 var valMap []bool 56 referenceSeriesExpr := e.GetNamedArg("referenceSeries") 57 if !referenceSeriesExpr.IsInterfaceNil() { 58 referenceSeries, err := helper.GetSeriesArg(ctx, eval, referenceSeriesExpr, from, until, values) 59 if err != nil { 60 return nil, err 61 } 62 63 if len(referenceSeries) == 0 { 64 return nil, fmt.Errorf("reference series is not a valid metric") 65 } 66 length := len(referenceSeries[0].Values) 67 if length != len(arg[0].Values) { 68 return nil, fmt.Errorf("length of series and reference series must be the same") 69 } 70 valMap = make([]bool, length) 71 72 for _, a := range referenceSeries { 73 for i, v := range a.Values { 74 if !math.IsNaN(v) { 75 valMap[i] = true 76 } 77 } 78 } 79 } 80 81 results := make([]*types.MetricData, 0, len(arg)+1) 82 for _, a := range arg { 83 var name string 84 if ok { 85 name = "transformNull(" + a.Name + "," + defvStr + ")" 86 } else { 87 name = "transformNull(" + a.Name + ")" 88 } 89 90 r := a.CopyLink() 91 r.Name = name 92 r.Values = make([]float64, len(a.Values)) 93 r.Tags["transformNull"] = defvStr 94 95 for i, v := range a.Values { 96 if math.IsNaN(v) { 97 if len(valMap) == 0 { 98 v = defv 99 } else if valMap[i] { 100 v = defv 101 } 102 } 103 104 r.Values[i] = v 105 } 106 107 results = append(results, r) 108 } 109 if len(arg) == 0 && defaultOnAbsent { 110 values := []float64{defv, defv} 111 step := until - from 112 name := e.ToString() 113 tags := tags.ExtractTags(types.ExtractName(name)) 114 tags["transformNull"] = defvStr 115 results = append(results, &types.MetricData{ 116 FetchResponse: pbv3.FetchResponse{ 117 Name: name, 118 StartTime: from, 119 StopTime: from + step*int64(len(values)), 120 StepTime: step, 121 Values: values, 122 }, 123 Tags: tags, 124 }) 125 } 126 return results, nil 127 } 128 129 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 130 func (f *transformNull) Description() map[string]types.FunctionDescription { 131 return map[string]types.FunctionDescription{ 132 "transformNull": { 133 Description: `Takes a metric or wildcard seriesList and replaces null values with the value 134 specified by 'default'. The value 0 used if not specified. The optional 135 referenceSeries, if specified, is a metric or wildcard series list that governs 136 which time intervals nulls should be replaced. If specified, nulls are replaced 137 only in intervals where a non-null is found for the same interval in any of 138 referenceSeries. This method compliments the drawNullAsZero function in 139 graphical mode, but also works in text-only mode. 140 defaultOnAbsent if specified, would produce a constant line if no metrics will be returned by backends. 141 Example: 142 .. code-block:: none 143 &target=transformNull(webapp.pages.*.views,-1) 144 This would take any page that didn't have values and supply negative 1 as a default. 145 Any other numeric value may be used as well. 146 `, 147 Function: "transformNull(seriesList, default=0, referenceSeries=None)", 148 Group: "Transform", 149 Module: "graphite.render.functions", 150 Name: "transformNull", 151 Params: []types.FunctionParam{ 152 { 153 Name: "seriesList", 154 Required: true, 155 Type: types.SeriesList, 156 }, 157 { 158 Default: types.NewSuggestion(0), 159 Name: "default", 160 Type: types.Float, 161 }, 162 { 163 Name: "referenceSeries", 164 Type: types.SeriesList, 165 }, 166 { 167 Name: "defaultOnAbsent", 168 Type: types.Boolean, 169 }, 170 }, 171 NameChange: true, // name changed 172 ValuesChange: true, // values changed 173 }, 174 } 175 }