github.com/go-graphite/carbonapi@v0.17.0/expr/functions/mostDeviant/function.go (about)

     1  package mostDeviant
     2  
     3  import (
     4  	"container/heap"
     5  	"context"
     6  	"math"
     7  
     8  	"github.com/go-graphite/carbonapi/expr/consolidations"
     9  	"github.com/go-graphite/carbonapi/expr/helper"
    10  	"github.com/go-graphite/carbonapi/expr/interfaces"
    11  	"github.com/go-graphite/carbonapi/expr/types"
    12  	"github.com/go-graphite/carbonapi/pkg/parser"
    13  )
    14  
    15  type mostDeviant struct{}
    16  
    17  func GetOrder() interfaces.Order {
    18  	return interfaces.Any
    19  }
    20  
    21  func New(configFile string) []interfaces.FunctionMetadata {
    22  	res := make([]interfaces.FunctionMetadata, 0)
    23  	f := &mostDeviant{}
    24  	functions := []string{"mostDeviant"}
    25  	for _, n := range functions {
    26  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    27  	}
    28  	return res
    29  }
    30  
    31  // mostDeviant(seriesList, n) -or- mostDeviant(n, seriesList)
    32  func (f *mostDeviant) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    33  	if e.ArgsLen() < 2 {
    34  		return nil, parser.ErrMissingArgument
    35  	}
    36  
    37  	var nArg int
    38  	if !e.Arg(0).IsConst() {
    39  		// mostDeviant(seriesList, n)
    40  		nArg = 1
    41  	}
    42  	seriesArg := nArg ^ 1 // XOR to make seriesArg the opposite argument. ( 0^1 -> 1 ; 1^1 -> 0 )
    43  
    44  	n, err := e.GetIntArg(nArg)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	args, err := helper.GetSeriesArg(ctx, eval, e.Arg(seriesArg), from, until, values)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	mh := make(types.MetricHeap, 0, len(args))
    55  
    56  	for index, arg := range args {
    57  		variance := consolidations.VarianceValue(arg.Values)
    58  		if math.IsNaN(variance) {
    59  			continue
    60  		}
    61  
    62  		if len(mh) < n {
    63  			heap.Push(&mh, types.MetricHeapElement{Idx: index, Val: variance})
    64  			continue
    65  		}
    66  
    67  		if variance > mh[0].Val {
    68  			mh[0].Idx = index
    69  			mh[0].Val = variance
    70  			heap.Fix(&mh, 0)
    71  		}
    72  	}
    73  
    74  	results := make([]*types.MetricData, len(mh))
    75  
    76  	for len(mh) > 0 {
    77  		v := heap.Pop(&mh).(types.MetricHeapElement)
    78  		results[len(mh)] = args[v.Idx]
    79  	}
    80  
    81  	return results, err
    82  }
    83  
    84  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
    85  func (f *mostDeviant) Description() map[string]types.FunctionDescription {
    86  	return map[string]types.FunctionDescription{
    87  		"mostDeviant": {
    88  			Description: "Takes one metric or a wildcard seriesList followed by an integer N.\nDraws the N most deviant metrics.\nTo find the deviants, the standard deviation (sigma) of each series\nis taken and ranked. The top N standard deviations are returned.\n\n  Example:\n\n.. code-block:: none\n\n  &target=mostDeviant(server*.instance*.memory.free, 5)\n\nDraws the 5 instances furthest from the average memory free.",
    89  			Function:    "mostDeviant(seriesList, n)",
    90  			Group:       "Filter Series",
    91  			Module:      "graphite.render.functions",
    92  			Name:        "mostDeviant",
    93  			Params: []types.FunctionParam{
    94  				{
    95  					Name:     "seriesList",
    96  					Required: true,
    97  					Type:     types.SeriesList,
    98  				},
    99  				{
   100  					Name:     "n",
   101  					Required: true,
   102  					Type:     types.Integer,
   103  				},
   104  			},
   105  			SeriesChange: true, // function aggregate metrics or change series items count
   106  		},
   107  	}
   108  }