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

     1  package compressPeriodicGaps
     2  
     3  import (
     4  	"context"
     5  	"math"
     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  )
    13  
    14  type compressPeriodicGaps 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 := &compressPeriodicGaps{}
    23  	functions := []string{"compressPeriodicGaps"}
    24  	for _, n := range functions {
    25  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    26  	}
    27  	return res
    28  }
    29  
    30  // compressPeriodicGaps(seriesList)
    31  func (f *compressPeriodicGaps) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    32  	args, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	var results []*types.MetricData
    37  
    38  	for _, a := range args {
    39  		firstSeen := -1
    40  		secondSeen := -1
    41  		interval := math.NaN()
    42  		name := "compressPeriodicGaps(" + a.Name + ")"
    43  
    44  		for i, v := range a.Values {
    45  			if !math.IsNaN(v) {
    46  				if firstSeen >= 0 {
    47  					secondSeen = i
    48  					break
    49  				} else {
    50  					firstSeen = i
    51  				}
    52  			}
    53  		}
    54  		stepGuess := secondSeen - firstSeen
    55  		thirdSeen := secondSeen + stepGuess
    56  		if stepGuess > 1 && thirdSeen <= len(a.Values)-2 {
    57  			if !math.IsNaN(a.Values[thirdSeen]) {
    58  				if math.IsNaN(a.Values[thirdSeen-1]) && math.IsNaN(a.Values[thirdSeen+1]) {
    59  					interval = float64(int64(stepGuess) * a.StepTime)
    60  				}
    61  			}
    62  		}
    63  
    64  		if math.IsNaN(interval) {
    65  			r := a.CopyLink()
    66  			r.Name = name
    67  			results = append(results, r)
    68  		} else {
    69  			newStart := a.StartTime + int64(firstSeen)*a.StepTime
    70  			newValues := make([]float64, 0, int64(interval)/a.StepTime)
    71  			ridx := 0
    72  			intervalItems := 0
    73  			intervalEnd := float64(newStart) + interval
    74  			t := a.StartTime // unadjusted
    75  			buckets := helper.GetBuckets(newStart, a.StopTime, int64(interval))
    76  
    77  			r := a.CopyLink()
    78  			r.Name = name
    79  			r.StepTime = int64(interval)
    80  			r.StartTime = newStart
    81  			r.Values = make([]float64, buckets)
    82  
    83  			for _, v := range a.Values {
    84  				intervalItems++
    85  				if !math.IsNaN(v) {
    86  					newValues = append(newValues, v)
    87  				}
    88  
    89  				t += a.StepTime
    90  
    91  				if t >= a.StopTime {
    92  					break
    93  				}
    94  
    95  				if t >= int64(intervalEnd) {
    96  					rv := consolidations.SummarizeValues("last", newValues, a.XFilesFactor)
    97  
    98  					r.Values[ridx] = rv
    99  					ridx++
   100  					intervalEnd += interval
   101  					intervalItems = 0
   102  					newValues = newValues[:0]
   103  				}
   104  			}
   105  
   106  			// last partial bucket
   107  			if intervalItems > 0 {
   108  				rv := consolidations.SummarizeValues("last", newValues, a.XFilesFactor)
   109  				r.Values[ridx] = rv
   110  			}
   111  
   112  			r.StopTime = r.StartTime + int64(len(r.Values))*r.StepTime
   113  			results = append(results, r)
   114  		}
   115  
   116  	}
   117  
   118  	return results, nil
   119  }
   120  
   121  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
   122  func (f *compressPeriodicGaps) Description() map[string]types.FunctionDescription {
   123  	return map[string]types.FunctionDescription{
   124  		"compressPeriodicGaps": {
   125  			Description: "Tries to intelligently remove periodic None’s from series, recalculating start, stop and step values.\n You can use summarize(seriesList, ‘<desired step>’, ‘last’) function for that also, but this function trying to guess desired step automatically.\n Can be used in case of fix metric with improper resolution. Especially useful for derivative functions, which are not working with series with regular gaps.\n\n.. code-block:: none\n\n &target=compressPeriodicGaps(Server.instance01.threads.busy)\n\n",
   126  			Function:    "compressPeriodicGaps(seriesList)",
   127  			Group:       "Transform",
   128  			Module:      "graphite.render.functions",
   129  			Name:        "compressPeriodicGaps",
   130  			Params: []types.FunctionParam{
   131  				{
   132  					Name:     "seriesList",
   133  					Required: true,
   134  					Type:     types.SeriesList,
   135  				},
   136  			},
   137  		},
   138  	}
   139  }