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

     1  package aliasQuery
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  
     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  type aliasQuery struct{}
    15  
    16  func GetOrder() interfaces.Order {
    17  	return interfaces.Any
    18  }
    19  
    20  func New(_ string) []interfaces.FunctionMetadata {
    21  	return []interfaces.FunctionMetadata{
    22  		{Name: "aliasQuery", F: &aliasQuery{}},
    23  	}
    24  }
    25  
    26  func (f *aliasQuery) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    27  	seriesList, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	search, err := e.GetStringArg(1)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	replace, err := e.GetStringArg(2)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	newName, err := e.GetStringArg(3)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	re, err := regexp.Compile(search)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	replace = helper.Backref.ReplaceAllString(replace, "$${$1}")
    49  
    50  	fetchTargets := make([]parser.Expr, len(seriesList))
    51  	for i, series := range seriesList {
    52  		newTarget := re.ReplaceAllString(series.Name, replace)
    53  		expr, _, err := parser.ParseExpr(newTarget)
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  		fetchTargets[i] = expr
    58  	}
    59  	targetValues, err := eval.Fetch(ctx, fetchTargets, from, until, values)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	results := make([]*types.MetricData, len(seriesList))
    65  
    66  	for i, series := range seriesList {
    67  		v, err := f.getLastValueOfSeries(ctx, eval, fetchTargets[i], from, until, targetValues)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		r := series.CopyLinkTags()
    72  		r.Name = fmt.Sprintf(newName, v)
    73  		results[i] = r
    74  	}
    75  
    76  	return results, nil
    77  }
    78  
    79  func (f *aliasQuery) getLastValueOfSeries(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, targetValues map[parser.MetricRequest][]*types.MetricData) (float64, error) {
    80  	res, err := helper.GetSeriesArg(ctx, eval, e, from, until, targetValues)
    81  	if err != nil {
    82  		return 0, err
    83  	}
    84  
    85  	if len(res) == 0 {
    86  		return 0, parser.ErrMissingTimeseries
    87  	}
    88  
    89  	if len(res[0].Values) == 0 {
    90  		return 0, parser.ErrMissingValues
    91  	}
    92  
    93  	return res[0].Values[len(res[0].Values)-1], nil
    94  }
    95  
    96  func (f *aliasQuery) Description() map[string]types.FunctionDescription {
    97  	return map[string]types.FunctionDescription{
    98  		"aliasQuery": {
    99  			Description: "Performs a query to alias the metrics in seriesList.\nThe series in seriesList will be aliased by first translating the series names using the search & replace parameters, then using the last value of the resulting series to construct the alias using sprintf-style syntax.",
   100  			Function:    "aliasQuery(seriesList, search, replace, newName)",
   101  			Group:       "Alias",
   102  			Module:      "graphite.render.functions",
   103  			Name:        "aliasQuery",
   104  			Params: []types.FunctionParam{
   105  				{
   106  					Name:     "seriesList",
   107  					Required: true,
   108  					Type:     types.SeriesList,
   109  				},
   110  				{
   111  					Name:     "search",
   112  					Required: true,
   113  					Type:     types.String,
   114  				},
   115  				{
   116  					Name:     "replace",
   117  					Required: true,
   118  					Type:     types.String,
   119  				},
   120  				{
   121  					Name:     "newName",
   122  					Required: true,
   123  					Type:     types.String,
   124  				},
   125  			},
   126  			NameChange: true,
   127  			TagsChange: true,
   128  		},
   129  	}
   130  }