github.com/go-graphite/carbonapi@v0.17.0/expr/rewrite/applyByNode/function.go (about) 1 package applyByNode 2 3 import ( 4 "context" 5 "strings" 6 7 "github.com/ansel1/merry" 8 "github.com/go-graphite/carbonapi/expr/helper" 9 "github.com/go-graphite/carbonapi/expr/interfaces" 10 "github.com/go-graphite/carbonapi/expr/types" 11 "github.com/go-graphite/carbonapi/pkg/parser" 12 ) 13 14 func GetOrder() interfaces.Order { 15 return interfaces.Any 16 } 17 18 type applyByNode struct { 19 interfaces.Function 20 } 21 22 func New(configFile string) []interfaces.RewriteFunctionMetadata { 23 res := make([]interfaces.RewriteFunctionMetadata, 0) 24 f := &applyByNode{} 25 for _, n := range []string{"applyByNode"} { 26 res = append(res, interfaces.RewriteFunctionMetadata{Name: n, F: f}) 27 } 28 return res 29 } 30 31 func (f *applyByNode) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) (bool, []string, error) { 32 args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values) 33 if err != nil { 34 return false, nil, err 35 } 36 37 nodeNum, err := e.GetIntArg(1) 38 if err != nil { 39 return false, nil, err 40 } 41 42 callback, err := e.GetStringArg(2) 43 if err != nil { 44 return false, nil, err 45 } 46 47 var newName string 48 if e.ArgsLen() == 4 { 49 newName, err = e.GetStringArg(3) 50 if err != nil { 51 return false, nil, err 52 } 53 } 54 55 rv := make([]string, 0, len(args)) 56 for _, a := range args { 57 var node string 58 metric := a.Tags["name"] 59 nodes := strings.Split(metric, ".") 60 if nodeNum >= len(nodes) { 61 // field overflow 62 err := merry.WithMessagef(parser.ErrInvalidArg, "name=%s: nodeNum must be less than %d", metric, len(nodes)) 63 return false, nil, err 64 } else { 65 node = strings.Join(nodes[0:nodeNum+1], ".") 66 } 67 newTarget := strings.ReplaceAll(callback, "%", node) 68 69 if newName != "" { 70 newTarget = "alias(" + newTarget + ",\"" + strings.ReplaceAll(newName, "%", node) + "\")" 71 } 72 rv = append(rv, newTarget) 73 } 74 return true, rv, nil 75 } 76 77 // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web 78 func (f *applyByNode) Description() map[string]types.FunctionDescription { 79 return map[string]types.FunctionDescription{ 80 "applyByNode": { 81 Name: "applyByNode", 82 Params: []types.FunctionParam{ 83 { 84 Name: "seriesList", 85 Required: true, 86 Type: types.SeriesList, 87 }, 88 { 89 Name: "nodeNum", 90 Required: true, 91 Type: types.Node, 92 }, 93 { 94 Name: "templateFunction", 95 Required: true, 96 Type: types.String, 97 }, 98 { 99 Name: "newName", 100 Type: types.String, 101 }, 102 }, 103 Module: "graphite.render.functions", 104 Description: "Takes a seriesList and applies some complicated function (described by a string), replacing templates with unique\nprefixes of keys from the seriesList (the key is all nodes up to the index given as `nodeNum`).\n\nIf the `newName` parameter is provided, the name of the resulting series will be given by that parameter, with any\n\"%\" characters replaced by the unique prefix.\n\nExample:\n\n.. code-block:: none\n\n &target=applyByNode(servers.*.disk.bytes_free,1,\"divideSeries(%.disk.bytes_free,sumSeries(%.disk.bytes_*))\")\n\nWould find all series which match `servers.*.disk.bytes_free`, then trim them down to unique series up to the node\ngiven by nodeNum, then fill them into the template function provided (replacing % by the prefixes).\n\nAdditional Examples:\n\nGiven keys of\n\n- `stats.counts.haproxy.web.2XX`\n- `stats.counts.haproxy.web.3XX`\n- `stats.counts.haproxy.web.5XX`\n- `stats.counts.haproxy.microservice.2XX`\n- `stats.counts.haproxy.microservice.3XX`\n- `stats.counts.haproxy.microservice.5XX`\n\nThe following will return the rate of 5XX's per service:\n\n.. code-block:: none\n\n applyByNode(stats.counts.haproxy.*.*XX, 3, \"asPercent(%.5XX, sumSeries(%.*XX))\", \"%.pct_5XX\")\n\nThe output series would have keys `stats.counts.haproxy.web.pct_5XX` and `stats.counts.haproxy.microservice.pct_5XX`.", 105 Function: "applyByNode(seriesList, nodeNum, templateFunction, newName=None)", 106 Group: "Combine", 107 }, 108 } 109 }