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

     1  package keepLastValue
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  	"strconv"
     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 keepLastValue struct{}
    15  
    16  func GetOrder() interfaces.Order {
    17  	return interfaces.Any
    18  }
    19  
    20  func New(configFile string) []interfaces.FunctionMetadata {
    21  	res := make([]interfaces.FunctionMetadata, 0)
    22  	f := &keepLastValue{}
    23  	functions := []string{"keepLastValue"}
    24  	for _, n := range functions {
    25  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    26  	}
    27  	return res
    28  }
    29  
    30  // keepLastValue(seriesList, limit=inf)
    31  func (f *keepLastValue) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    32  
    33  	arg, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	var keep parser.IntOrInf
    39  	var keepStr string
    40  
    41  	keep, err = e.GetIntOrInfNamedOrPosArgDefault("limit", 1, parser.IntOrInf{IsInf: true})
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	if !keep.IsInf {
    47  		keepStr = strconv.Itoa(keep.IntVal)
    48  	} else {
    49  		keepStr = "inf"
    50  	}
    51  
    52  	var results []*types.MetricData
    53  
    54  	for _, a := range arg {
    55  		var name string
    56  		if e.ArgsLen() < 2 {
    57  			name = "keepLastValue(" + a.Name + ")"
    58  		} else {
    59  			name = "keepLastValue(" + a.Name + "," + keepStr + ")"
    60  		}
    61  
    62  		r := a.CopyLinkTags()
    63  		r.Name = name
    64  		r.Values = make([]float64, len(a.Values))
    65  
    66  		prev := math.NaN()
    67  		missing := 0
    68  
    69  		for i, v := range a.Values {
    70  			if math.IsNaN(v) {
    71  
    72  				if (keep.IsInf || keep.IntVal < 0 || missing < keep.IntVal) && !math.IsNaN(prev) {
    73  					r.Values[i] = prev
    74  					missing++
    75  				} else {
    76  					r.Values[i] = math.NaN()
    77  				}
    78  
    79  				continue
    80  			}
    81  			missing = 0
    82  			prev = v
    83  			r.Values[i] = v
    84  		}
    85  		results = append(results, r)
    86  	}
    87  	return results, err
    88  }
    89  
    90  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
    91  func (f *keepLastValue) Description() map[string]types.FunctionDescription {
    92  	return map[string]types.FunctionDescription{
    93  		"keepLastValue": {
    94  			Description: "Takes one metric or a wildcard seriesList, and optionally a limit to the number of 'None' values to skip over.\nContinues the line with the last received value when gaps ('None' values) appear in your data, rather than breaking your line.\n\nExample:\n\n.. code-block:: none\n\n  &target=keepLastValue(Server01.connections.handled)\n  &target=keepLastValue(Server01.connections.handled, 10)",
    95  			Function:    "keepLastValue(seriesList, limit=inf)",
    96  			Group:       "Transform",
    97  			Module:      "graphite.render.functions",
    98  			Name:        "keepLastValue",
    99  			Params: []types.FunctionParam{
   100  				{
   101  					Name:     "seriesList",
   102  					Required: true,
   103  					Type:     types.SeriesList,
   104  				},
   105  				{
   106  					Default: types.NewSuggestion(math.Inf(1)),
   107  					Name:    "limit",
   108  					Type:    types.IntOrInf,
   109  				},
   110  			},
   111  			SeriesChange: true, // function aggregate metrics or change series items count
   112  			NameChange:   true, // name changed
   113  			ValuesChange: true, // values changed
   114  		},
   115  	}
   116  }