github.com/go-graphite/carbonapi@v0.17.0/expr/functions/sortBy/function.go (about) 1 package sortBy 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "sort" 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 sortBy struct{} 17 18 func GetOrder() interfaces.Order { 19 return interfaces.Any 20 } 21 22 func New(configFile string) []interfaces.FunctionMetadata { 23 res := make([]interfaces.FunctionMetadata, 0) 24 f := &sortBy{} 25 functions := []string{"sortByMaxima", "sortByMinima", "sortByTotal", "sortBy"} 26 for _, n := range functions { 27 res = append(res, interfaces.FunctionMetadata{Name: n, F: f}) 28 } 29 return res 30 } 31 32 // sortByMaxima(seriesList), sortByMinima(seriesList), sortByTotal(seriesList) 33 func (f *sortBy) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) { 34 original, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 35 if err != nil { 36 return nil, err 37 } 38 39 reverse, err := e.GetBoolArgDefault(2, false) 40 if err != nil { 41 return nil, err 42 } 43 ascending := !reverse 44 45 sortByFunc, err := e.GetStringArgDefault(1, "average") 46 if err != nil { 47 return nil, err 48 } 49 50 aggFuncMap := map[string]struct { 51 name string 52 ascending bool 53 }{ 54 "sortByTotal": {"sum", false}, 55 "sortByMaxima": {"max", false}, 56 "sortByMinima": {"min", true}, 57 "sortBy": {sortByFunc, true}, 58 } 59 60 target := e.Target() 61 aggFunc, exists := aggFuncMap[target] 62 if !exists { 63 return nil, fmt.Errorf("invalid function called: %s", target) 64 } 65 if err := consolidations.CheckValidConsolidationFunc(aggFunc.name); err != nil { 66 return nil, err 67 } 68 69 // some function by default are not ascending so we need to reverse behaviour 70 if !aggFunc.ascending { 71 ascending = !ascending 72 } 73 74 return doSort(aggFunc.name, ascending, original), nil 75 } 76 77 func doSort(aggFuncName string, ascending bool, original []*types.MetricData) []*types.MetricData { 78 arg := make([]*types.MetricData, len(original)) 79 copy(arg, original) 80 vals := make([]float64, len(arg)) 81 82 for i, a := range arg { 83 vals[i] = consolidations.SummarizeValues(aggFuncName, a.Values, a.XFilesFactor) 84 if math.IsNaN(vals[i]) { 85 vals[i] = math.Inf(-1) 86 } 87 } 88 89 if ascending { 90 sort.Sort(helper.ByVals{Vals: vals, Series: arg}) 91 } else { 92 sort.Sort(sort.Reverse(helper.ByVals{Vals: vals, Series: arg})) 93 } 94 95 return arg 96 } 97 98 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 99 func (f *sortBy) Description() map[string]types.FunctionDescription { 100 return map[string]types.FunctionDescription{ 101 "sortByMaxima": { 102 Description: "Takes one metric or a wildcard seriesList.\n\nSorts the list of metrics in descending order by the maximum value across the time period\nspecified. Useful with the &areaMode=all parameter, to keep the\nlowest value lines visible.\n\nExample:\n\n.. code-block:: none\n\n &target=sortByMaxima(server*.instance*.memory.free)", 103 Function: "sortByMaxima(seriesList)", 104 Group: "Sorting", 105 Module: "graphite.render.functions", 106 Name: "sortByMaxima", 107 Params: []types.FunctionParam{ 108 { 109 Name: "seriesList", 110 Required: true, 111 Type: types.SeriesList, 112 }, 113 }, 114 }, 115 "sortByMinima": { 116 Description: "Takes one metric or a wildcard seriesList.\n\nSorts the list of metrics by the lowest value across the time period\nspecified, including only series that have a maximum value greater than 0.\n\nExample:\n\n.. code-block:: none\n\n &target=sortByMinima(server*.instance*.memory.free)", 117 Function: "sortByMinima(seriesList)", 118 Group: "Sorting", 119 Module: "graphite.render.functions", 120 Name: "sortByMinima", 121 Params: []types.FunctionParam{ 122 { 123 Name: "seriesList", 124 Required: true, 125 Type: types.SeriesList, 126 }, 127 }, 128 }, 129 "sortByTotal": { 130 Description: "Takes one metric or a wildcard seriesList.\n\nSorts the list of metrics in descending order by the sum of values across the time period\nspecified.", 131 Function: "sortByTotal(seriesList)", 132 Group: "Sorting", 133 Module: "graphite.render.functions", 134 Name: "sortByTotal", 135 Params: []types.FunctionParam{ 136 { 137 Name: "seriesList", 138 Required: true, 139 Type: types.SeriesList, 140 }, 141 }, 142 }, 143 "sortBy": { 144 Description: "Takes one metric or a wildcard seriesList followed by an aggregation function and an optional reverse parameter.\nReturns the metrics sorted according to the specified function.", 145 Function: "sortBy(seriesList, func='average', reverse=False)", 146 Group: "Sorting", 147 Module: "graphite.render.functions", 148 Name: "sortBy", 149 Params: []types.FunctionParam{ 150 { 151 Name: "seriesList", 152 Required: true, 153 Type: types.SeriesList, 154 }, 155 { 156 Name: "func", 157 Required: false, 158 Type: types.AggFunc, 159 }, 160 { 161 Name: "reverse", 162 Required: false, 163 Type: types.Boolean, 164 }, 165 }, 166 }, 167 } 168 }