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

     1  package smartSummarize
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/go-graphite/carbonapi/expr/consolidations"
     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  	pb "github.com/go-graphite/protocol/carbonapi_v3_pb"
    13  )
    14  
    15  type smartSummarize 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 := &smartSummarize{}
    24  	functions := []string{"smartSummarize"}
    25  	for _, n := range functions {
    26  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    27  	}
    28  	return res
    29  }
    30  
    31  // smartSummarize(seriesList, intervalString, func='sum', alignTo=None)
    32  func (f *smartSummarize) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    33  	// TODO(dgryski): make sure the arrays are all the same 'size'
    34  	if e.ArgsLen() < 2 {
    35  		return nil, parser.ErrMissingArgument
    36  	}
    37  
    38  	alignToInterval, err := e.GetStringNamedOrPosArgDefault("alignTo", 3, "")
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	if alignToInterval != "" {
    44  		// Note: the start time for the fetch request is adjusted in expr.Metrics() so that the fetched
    45  		// data is already aligned by interval if this parameter specifics an interval to align to
    46  		newStart, err := parser.StartAlignTo(from, alignToInterval)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  		from = newStart
    51  	}
    52  	args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	if len(args) == 0 {
    58  		return []*types.MetricData{}, nil
    59  	}
    60  
    61  	bucketSizeInt32, err := e.GetIntervalArg(1, 1)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	if bucketSizeInt32 <= 0 {
    66  		return nil, parser.ErrInvalidInterval
    67  	}
    68  	bucketSize := int64(bucketSizeInt32)
    69  	bucketSizeStr := e.Arg(1).StringValue()
    70  
    71  	summarizeFunction, err := e.GetStringNamedOrPosArgDefault("func", 2, "sum")
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	if err := consolidations.CheckValidConsolidationFunc(summarizeFunction); err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	results := make([]*types.MetricData, len(args))
    80  	for n, arg := range args {
    81  		var name string
    82  
    83  		if alignToInterval != "" {
    84  			name = "smartSummarize(" + arg.Name + ",'" + bucketSizeStr + "','" + summarizeFunction + "','" + alignToInterval + "')"
    85  		} else {
    86  			name = "smartSummarize(" + arg.Name + ",'" + bucketSizeStr + "','" + summarizeFunction + "')"
    87  		}
    88  
    89  		r := types.MetricData{
    90  			FetchResponse: pb.FetchResponse{
    91  				Name:              name,
    92  				StepTime:          bucketSize,
    93  				StartTime:         arg.StartTime,
    94  				StopTime:          arg.StopTime,
    95  				ConsolidationFunc: arg.ConsolidationFunc,
    96  			},
    97  			Tags: helper.CopyTags(arg),
    98  		}
    99  		r.Tags["smartSummarize"] = fmt.Sprintf("%d", bucketSizeInt32)
   100  		r.Tags["smartSummarizeFunction"] = summarizeFunction
   101  
   102  		ts := arg.StartTime
   103  		for ts < arg.StopTime {
   104  			bucketUpperBound := ts + bucketSize
   105  			bucketStart := (ts - arg.StartTime + arg.StepTime - 1) / arg.StepTime             // equivalent to ceil((ts-arg.StartTime) / arg.StepTime)
   106  			bucketEnd := (bucketUpperBound - arg.StartTime + arg.StepTime - 1) / arg.StepTime // equivalent to ceil((until-arg.StartTime) / arg.StepTime)
   107  
   108  			if bucketEnd > int64(len(arg.Values)) {
   109  				bucketEnd = int64(len(arg.Values))
   110  			}
   111  
   112  			rv := consolidations.SummarizeValues(summarizeFunction, arg.Values[bucketStart:bucketEnd], arg.XFilesFactor)
   113  			r.Values = append(r.Values, rv)
   114  			ts = bucketUpperBound
   115  		}
   116  		r.StopTime = ts
   117  		results[n] = &r
   118  	}
   119  	return results, nil
   120  }
   121  
   122  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
   123  func (f *smartSummarize) Description() map[string]types.FunctionDescription {
   124  	return map[string]types.FunctionDescription{
   125  		"smartSummarize": {
   126  			Description: "Smarter version of summarize.\nThe alignToFrom boolean parameter has been replaced by alignTo and no longer has any effect. Alignment can be to years, months, weeks, days, hours, and minutes.\nThis function can be used with aggregation functions average, median, sum, min, max, diff, stddev, count, range, multiply & last.",
   127  			Function:    "smartSummarize(seriesList, intervalString, func='sum', alignTo=None)",
   128  			Group:       "Transform",
   129  			Module:      "graphite.render.functions",
   130  			Name:        "smartSummarize",
   131  			Params: []types.FunctionParam{
   132  				{
   133  					Name:     "seriesList",
   134  					Required: true,
   135  					Type:     types.SeriesList,
   136  				},
   137  				{
   138  					Name:     "intervalString",
   139  					Required: true,
   140  					Suggestions: types.NewSuggestions(
   141  						"10min",
   142  						"1h",
   143  						"1d",
   144  					),
   145  					Type: types.Interval,
   146  				},
   147  				{
   148  					Default: types.NewSuggestion("sum"),
   149  					Name:    "func",
   150  					Options: types.StringsToSuggestionList(consolidations.AvailableSummarizers),
   151  					Type:    types.AggFunc,
   152  				},
   153  				{
   154  					Name: "alignTo",
   155  					Suggestions: types.NewSuggestions(
   156  						"1m",
   157  						"1d",
   158  						"1y",
   159  					),
   160  					Type: types.Interval,
   161  				},
   162  			},
   163  			NameChange:   true, // name changed
   164  			ValuesChange: true, // values changed
   165  		},
   166  	}
   167  }