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  }