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

     1  package holtWintersAberration
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  
     7  	"github.com/go-graphite/carbonapi/expr/helper"
     8  	"github.com/go-graphite/carbonapi/expr/holtwinters"
     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 holtWintersAberration 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 := &holtWintersAberration{}
    24  	functions := []string{"holtWintersAberration"}
    25  	for _, n := range functions {
    26  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    27  	}
    28  	return res
    29  }
    30  
    31  func (f *holtWintersAberration) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    32  	bootstrapInterval, err := e.GetIntervalNamedOrPosArgDefault("bootstrapInterval", 2, 1, holtwinters.DefaultBootstrapInterval)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	// Note: additional fetch requests are added with an adjusted start time in expr.Metrics() (in
    43  	// pkg/parser/parser.go) so that the appropriate data corresponding to the adjusted start time
    44  	// can be pre-fetched.
    45  	adjustedStartArgs, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from-bootstrapInterval, until, values)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	adjustedStartSeries := make(map[string]*types.MetricData)
    51  	for _, serie := range adjustedStartArgs {
    52  		adjustedStartSeries[serie.Name] = serie
    53  	}
    54  
    55  	delta, err := e.GetFloatNamedOrPosArgDefault("delta", 1, 3)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	seasonality, err := e.GetIntervalNamedOrPosArgDefault("seasonality", 3, 1, holtwinters.DefaultSeasonality)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	results := make([]*types.MetricData, 0, len(args))
    66  	for _, arg := range args {
    67  		var (
    68  			aberration []float64
    69  		)
    70  
    71  		stepTime := arg.StepTime
    72  
    73  		if v, ok := adjustedStartSeries[arg.Name]; !ok || v == nil {
    74  			continue
    75  		}
    76  
    77  		lowerBand, upperBand := holtwinters.HoltWintersConfidenceBands(adjustedStartSeries[arg.Name].Values, stepTime, delta, bootstrapInterval, seasonality)
    78  
    79  		for i, v := range arg.Values {
    80  			if math.IsNaN(v) {
    81  				aberration = append(aberration, 0)
    82  			} else if !math.IsNaN(upperBand[i]) && v > upperBand[i] {
    83  				aberration = append(aberration, v-upperBand[i])
    84  			} else if !math.IsNaN(lowerBand[i]) && v < lowerBand[i] {
    85  				aberration = append(aberration, v-lowerBand[i])
    86  			} else {
    87  				aberration = append(aberration, 0)
    88  			}
    89  		}
    90  
    91  		name := "holtWintersAberration(" + arg.Name + ")"
    92  		r := types.MetricData{
    93  			FetchResponse: pb.FetchResponse{
    94  				Name:              name,
    95  				Values:            aberration,
    96  				StepTime:          arg.StepTime,
    97  				StartTime:         arg.StartTime,
    98  				StopTime:          arg.StopTime,
    99  				PathExpression:    name,
   100  				ConsolidationFunc: arg.ConsolidationFunc,
   101  				XFilesFactor:      arg.XFilesFactor,
   102  			},
   103  			Tags: helper.CopyTags(arg),
   104  		}
   105  		r.Tags["holtWintersAberration"] = "1"
   106  		results = append(results, &r)
   107  	}
   108  	return results, nil
   109  }
   110  
   111  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
   112  func (f *holtWintersAberration) Description() map[string]types.FunctionDescription {
   113  	return map[string]types.FunctionDescription{
   114  		"holtWintersAberration": {
   115  			Description: "Performs a Holt-Winters forecast using the series as input data and plots the\npositive or negative deviation of the series data from the forecast.",
   116  			Function:    "holtWintersAberration(seriesList, delta=3, bootstrapInterval='7d')",
   117  			Group:       "Calculate",
   118  			Module:      "graphite.render.functions",
   119  			Name:        "holtWintersAberration",
   120  			Params: []types.FunctionParam{
   121  				{
   122  					Name:     "seriesList",
   123  					Required: true,
   124  					Type:     types.SeriesList,
   125  				},
   126  				{
   127  					Default: types.NewSuggestion(3),
   128  					Name:    "delta",
   129  					Type:    types.Integer,
   130  				},
   131  				{
   132  					Default: types.NewSuggestion("7d"),
   133  					Name:    "bootstrapInterval",
   134  					Suggestions: types.NewSuggestions(
   135  						"7d",
   136  						"30d",
   137  					),
   138  					Type: types.Interval,
   139  				},
   140  			},
   141  			SeriesChange: true, // function aggregate metrics or change series items count
   142  			NameChange:   true, // name changed
   143  			TagsChange:   true, // name tag changed
   144  			ValuesChange: true, // values changed
   145  		},
   146  	}
   147  }