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

     1  package aggregateWithWildcards
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     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 aggregateWithWildcards struct{}
    16  
    17  func GetOrder() interfaces.Order {
    18  	return interfaces.Any
    19  }
    20  
    21  func New(configFile string) []interfaces.FunctionMetadata {
    22  	f := &aggregateWithWildcards{}
    23  	res := make([]interfaces.FunctionMetadata, 0)
    24  	for _, n := range []string{"multiplySeriesWithWildcards", "averageSeriesWithWildcards", "aggregateWithWildcards", "sumSeriesWithWildcards"} {
    25  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    26  	}
    27  	return res
    28  }
    29  
    30  func (f *aggregateWithWildcards) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    31  	if e.ArgsLen() < 2 {
    32  		return nil, parser.ErrMissingArgument
    33  	}
    34  
    35  	args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	var callback string
    41  	fieldsArgsIx := 1
    42  	switch e.Target() {
    43  	case "aggregateWithWildcards":
    44  		callback, err = e.GetStringArg(1)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		fieldsArgsIx = 2
    49  	case "sumSeriesWithWildcards":
    50  		callback = "sum"
    51  	case "averageSeriesWithWildcards":
    52  		callback = "average"
    53  	case "multiplySeriesWithWildcards":
    54  		callback = "multiply"
    55  	}
    56  
    57  	var fields []int
    58  	fields, err = e.GetIntArgs(fieldsArgsIx)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	aggFunc, ok := consolidations.ConsolidationToFunc[callback]
    64  	if !ok {
    65  		return nil, fmt.Errorf("unsupported consolidation function %s", callback)
    66  	}
    67  	groups := make(map[string][]*types.MetricData)
    68  	nodeList := make([]string, 0, 256)
    69  
    70  	for _, a := range args {
    71  		metric := types.ExtractNameTag(a.Name)
    72  		nodes := strings.Split(metric, ".")
    73  		s := make([]string, 0, len(nodes))
    74  		// Yes, this is O(n^2), but len(nodes) < 10 and len(fields) < 3
    75  		// Iterating an int slice is faster than a map for n ~ 30
    76  		// http://www.antoine.im/posts/someone_is_wrong_on_the_internet
    77  		for i, n := range nodes {
    78  			if !helper.Contains(fields, i) {
    79  				s = append(s, n)
    80  			}
    81  		}
    82  
    83  		node := strings.Join(s, ".")
    84  
    85  		if len(groups[node]) == 0 {
    86  			nodeList = append(nodeList, node)
    87  		}
    88  
    89  		groups[node] = append(groups[node], a)
    90  	}
    91  
    92  	results := make([]*types.MetricData, 0, len(groups))
    93  
    94  	for _, node := range nodeList {
    95  		// Pass in -1 for xFilesFactor because aggregateWithWildcards doesn't support xFilesFactor
    96  		res, err := helper.AggregateSeries(e, groups[node], aggFunc, -1, false)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		res[0].Name = node
   101  		res[0].Tags["aggregatedBy"] = callback
   102  
   103  		results = append(results, res...)
   104  	}
   105  
   106  	return results, nil
   107  }
   108  
   109  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
   110  func (f *aggregateWithWildcards) Description() map[string]types.FunctionDescription {
   111  	return map[string]types.FunctionDescription{
   112  		"aggregateWithWildcards": {
   113  			Name:        "aggregateWithWildcards",
   114  			Function:    "aggregateWithWildcards(seriesList, func, *positions)",
   115  			Description: "Call aggregator after inserting wildcards at the given position(s).\n\nExample:\n\n.. code-block:: none\n\n &target=aggregateWithWildcards(host.cpu-[0-7].cpu-{user,system}.value, 'sum', 1)",
   116  			Module:      "graphite.render.functions",
   117  			Group:       "Calculate",
   118  			Params: []types.FunctionParam{
   119  				{
   120  					Name:     "seriesList",
   121  					Type:     types.SeriesList,
   122  					Required: true,
   123  				},
   124  				{
   125  					Name:     "func",
   126  					Type:     types.AggFunc,
   127  					Required: true,
   128  					Options:  types.StringsToSuggestionList(consolidations.AvailableConsolidationFuncs()),
   129  				},
   130  				{
   131  					Name:     "positions",
   132  					Type:     types.Node,
   133  					Required: true,
   134  				},
   135  			},
   136  		},
   137  		"averageSeriesWithWildcards": {
   138  			Description: "Call averageSeries after inserting wildcards at the given position(s).\n\nExample:\n\n.. code-block:: none\n\n  &target=averageSeriesWithWildcards(host.cpu-[0-7}.cpu-{user,system}.value, 1)\n\nThis would be the equivalent of\n\n.. code-block:: none\n\n  &target=averageSeries(host.*.cpu-user.value)&target=averageSeries(host.*.cpu-system.value)\n\nThis is an alias for :py:func:`aggregateWithWildcards <aggregateWithWildcards>` with aggregation ``average``.",
   139  			Function:    "averageSeriesWithWildcards(seriesList, *position)",
   140  			Group:       "Combine",
   141  			Module:      "graphite.render.functions",
   142  			Name:        "averageSeriesWithWildcards",
   143  			Params: []types.FunctionParam{
   144  				{
   145  					Name:     "seriesList",
   146  					Required: true,
   147  					Type:     types.SeriesList,
   148  				},
   149  				{
   150  					Multiple: true,
   151  					Name:     "position",
   152  					Type:     types.Node,
   153  				},
   154  			},
   155  			SeriesChange: true, // function aggregate metrics or change series items count
   156  			NameChange:   true, // name changed
   157  			TagsChange:   true, // name tag changed
   158  			ValuesChange: true, // values changed
   159  		},
   160  		"multiplySeriesWithWildcards": {
   161  			Description: "Call multiplySeries after inserting wildcards at the given position(s).\n\nExample:\n\n.. code-block:: none\n\n  &target=multiplySeriesWithWildcards(web.host-[0-7}.{avg-response,total-request}.value, 2)\n\nThis would be the equivalent of\n\n.. code-block:: none\n\n  &target=multiplySeries(web.host-0.{avg-response,total-request}.value)&target=multiplySeries(web.host-1.{avg-response,total-request}.value)...\n\nThis is an alias for :py:func:`aggregateWithWildcards <aggregateWithWildcards>` with aggregation ``multiply``.",
   162  			Function:    "multiplySeriesWithWildcards(seriesList, *position)",
   163  			Group:       "Combine",
   164  			Module:      "graphite.render.functions",
   165  			Name:        "multiplySeriesWithWildcards",
   166  			Params: []types.FunctionParam{
   167  				{
   168  					Name:     "seriesList",
   169  					Required: true,
   170  					Type:     types.SeriesList,
   171  				},
   172  				{
   173  					Multiple: true,
   174  					Name:     "position",
   175  					Type:     types.Node,
   176  				},
   177  			},
   178  			SeriesChange: true, // function aggregate metrics or change series items count
   179  			NameChange:   true, // name changed
   180  			TagsChange:   true, // name tag changed
   181  			ValuesChange: true, // values changed
   182  		},
   183  		"sumSeriesWithWildcards": {
   184  			Description: "Call sumSeries after inserting wildcards at the given position(s).\n\nExample:\n\n.. code-block:: none\n\n  &target=sumSeriesWithWildcards(host.cpu-[0-7}.cpu-{user,system}.value, 1)\n\nThis would be the equivalent of\n\n.. code-block:: none\n\n  &target=sumSeries(host.cpu-[0-7}.cpu-user.value)&target=sumSeries(host.cpu-[0-7}.cpu-system.value)\n\nThis is an alias for :py:func:`aggregateWithWildcards <aggregateWithWildcards>` with aggregation ``sum``.",
   185  			Function:    "sumSeriesWithWildcards(seriesList, *position)",
   186  			Group:       "Combine",
   187  			Module:      "graphite.render.functions",
   188  			Name:        "sumSeriesWithWildcards",
   189  			Params: []types.FunctionParam{
   190  				{
   191  					Name:     "seriesList",
   192  					Required: true,
   193  					Type:     types.SeriesList,
   194  				},
   195  				{
   196  					Multiple: true,
   197  					Name:     "position",
   198  					Type:     types.Node,
   199  				},
   200  			},
   201  			SeriesChange: true, // function aggregate metrics or change series items count
   202  			NameChange:   true, // name changed
   203  			TagsChange:   true, // name tag changed
   204  			ValuesChange: true, // values changed
   205  		},
   206  	}
   207  }