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

     1  package integralWithReset
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  
     7  	"github.com/ansel1/merry"
     8  
     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 integralWithReset 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 := &integralWithReset{}
    24  	functions := []string{"integralWithReset"}
    25  	for _, n := range functions {
    26  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    27  	}
    28  	return res
    29  }
    30  
    31  // integralWithReset(seriesList, resettingSeries)
    32  func (f *integralWithReset) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    33  	arg, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	resettingSeriesList, err := helper.GetSeriesArg(ctx, eval, e.Arg(1), from, until, values)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	if len(resettingSeriesList) != 1 {
    42  		return nil, types.ErrWildcardNotAllowed
    43  	}
    44  	resettingSeries := resettingSeriesList[0]
    45  
    46  	for _, a := range arg {
    47  		if a.StepTime != resettingSeries.StepTime || len(a.Values) != len(resettingSeries.Values) {
    48  			return nil, merry.Errorf("series %s must have the same length as %s", a.Name, resettingSeries.Name)
    49  		}
    50  	}
    51  
    52  	results := make([]*types.MetricData, len(arg))
    53  	for i, a := range arg {
    54  		r := a.CopyLinkTags()
    55  		r.Name = "integralWithReset(" + a.Name + "," + resettingSeries.Name + ")"
    56  		r.Values = make([]float64, len(a.Values))
    57  
    58  		current := 0.0
    59  		for i, v := range a.Values {
    60  			if math.IsNaN(v) {
    61  				r.Values[i] = v
    62  				continue
    63  			}
    64  			if !math.IsNaN(resettingSeries.Values[i]) && resettingSeries.Values[i] != 0 {
    65  				current = 0
    66  			} else {
    67  				current += v
    68  			}
    69  			r.Values[i] = current
    70  		}
    71  		results[i] = r
    72  	}
    73  	return results, nil
    74  }
    75  
    76  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
    77  func (f *integralWithReset) Description() map[string]types.FunctionDescription {
    78  	return map[string]types.FunctionDescription{
    79  		"integralWithReset": {
    80  			Description: "Just like integral(seriesList) but with resets: every time resettingSeries is not 0, the integral resets to 0.",
    81  			Function:    "integralWithReset(seriesList, resettingSeries)",
    82  			Group:       "Transform",
    83  			Module:      "graphite.render.functions",
    84  			Name:        "integralWithReset",
    85  			Params: []types.FunctionParam{
    86  				{
    87  					Name:     "seriesList",
    88  					Required: true,
    89  					Type:     types.SeriesList,
    90  				},
    91  				{
    92  					Name:     "resettingSeries",
    93  					Required: true,
    94  					Type:     types.SeriesList,
    95  				},
    96  			},
    97  			NameChange:   true, // name changed
    98  			ValuesChange: true, // values changed
    99  		},
   100  	}
   101  }