github.com/go-graphite/carbonapi@v0.17.0/expr/functions/aggregateLine/function.go (about) 1 package aggregateLine 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "strconv" 8 9 "github.com/go-graphite/carbonapi/expr/consolidations" 10 "github.com/go-graphite/carbonapi/expr/helper" 11 "github.com/go-graphite/carbonapi/expr/interfaces" 12 "github.com/go-graphite/carbonapi/expr/types" 13 "github.com/go-graphite/carbonapi/pkg/parser" 14 ) 15 16 type aggregateLine struct{} 17 18 func GetOrder() interfaces.Order { 19 return interfaces.Any 20 } 21 22 func New(configFile string) []interfaces.FunctionMetadata { 23 f := &aggregateLine{} 24 res := make([]interfaces.FunctionMetadata, 0) 25 for _, n := range []string{"aggregateLine"} { 26 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 27 } 28 return res 29 } 30 31 // aggregateLine(*seriesLists) 32 func (f *aggregateLine) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 33 args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 34 if err != nil { 35 return nil, err 36 } 37 38 callback := "avg" 39 keepStep := false 40 switch e.ArgsLen() { 41 case 2: 42 callback, err = e.GetStringArgDefault(1, "average") 43 if err != nil { 44 return nil, err 45 } 46 case 3: 47 callback, err = e.GetStringArgDefault(1, "average") 48 if err != nil { 49 return nil, err 50 } 51 52 keepStep, err = e.GetBoolArgDefault(2, false) 53 if err != nil { 54 return nil, err 55 } 56 } 57 58 aggFunc, ok := consolidations.ConsolidationToFunc[callback] 59 if !ok { 60 return nil, fmt.Errorf("unsupported consolidation function %s", callback) 61 } 62 63 results := make([]*types.MetricData, len(args)) 64 for i, a := range args { 65 var name string 66 67 val := aggFunc(a.Values) 68 if !math.IsNaN(val) { 69 name = "aggregateLine(" + a.Name + ", " + strconv.FormatFloat(val, 'g', -1, 64) + ")" 70 } else { 71 name = "aggregateLine(" + a.Name + ", None)" 72 } 73 74 r := a.CopyTag(name, a.Tags) 75 76 if keepStep { 77 r.Values = make([]float64, len(a.Values)) 78 for i := range r.Values { 79 r.Values[i] = val 80 } 81 } else { 82 r.StepTime = a.StopTime - a.FetchResponse.StartTime 83 r.Values = []float64{val, val} 84 r.StopTime = r.StartTime + int64(len(r.FetchResponse.Values))*r.FetchResponse.StepTime 85 } 86 87 results[i] = r 88 } 89 90 return results, nil 91 } 92 93 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 94 func (f *aggregateLine) Description() map[string]types.FunctionDescription { 95 return map[string]types.FunctionDescription{ 96 "aggregateLine": { 97 Name: "aggregateLine", 98 Function: "aggregateLine(seriesList, func='average', keepStep=False)", 99 Description: "Takes a metric or wildcard seriesList and draws a horizontal line\nbased on the function applied to each series.\n\nIf the optional keepStep parameter is set to True, the result will\nhave the same time period and step as the source series.\n\nNote: By default, the graphite renderer consolidates data points by\naveraging data points over time. If you are using the 'min' or 'max'\nfunction for aggregateLine, this can cause an unusual gap in the\nline drawn by this function and the data itself. To fix this, you\nshould use the consolidateBy() function with the same function\nargument you are using for aggregateLine. This will ensure that the\nproper data points are retained and the graph should line up\ncorrectly.\n\nExample:\n\n.. code-block:: none\n\n &target=aggregateLine(server01.connections.total, 'avg')\n &target=aggregateLine(server*.connections.total, 'avg')", 100 Module: "graphite.render.functions", 101 Group: "Calculate", 102 Params: []types.FunctionParam{ 103 { 104 Name: "seriesList", 105 Type: types.SeriesList, 106 Required: true, 107 }, 108 { 109 Name: "func", 110 Type: types.AggFunc, 111 Required: false, 112 Options: types.StringsToSuggestionList(consolidations.AvailableConsolidationFuncs()), 113 Default: &types.Suggestion{ 114 Value: "average", 115 Type: types.SString, 116 }, 117 }, 118 { 119 Name: "keepStep", 120 Type: types.Boolean, 121 Default: &types.Suggestion{ 122 Value: false, 123 Type: types.SBool, 124 }, 125 }, 126 }, 127 SeriesChange: true, // function aggregate metrics or change series items count 128 NameChange: true, // name changed 129 TagsChange: true, // name tag changed 130 ValuesChange: true, // values changed 131 }, 132 } 133 }